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

Last change on this file since 800 was 800, checked in by rlacroix, 5 years ago

Allow restarting a simulation in append mode with file splitting enabled.

Make use of the new registry to save the start and end dates of the last output file.

  • 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: 20.6 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      if (!split_freq.isEmpty())
183      {
184        if (context->registryIn->foundKey("splitStart") && context->registryIn->foundKey("splitEnd"))
185        {
186          string savedSplitStartStr, savedSplitEndStr;
187          context->registryIn->getKey("splitStart", savedSplitStartStr);
188          context->registryIn->getKey("splitEnd",   savedSplitEndStr);
189
190          CDate savedSplitStart = CDate::FromString(savedSplitStartStr, *context->getCalendar());
191          CDate savedSplitEnd = CDate::FromString(savedSplitEndStr, *context->getCalendar());
192          if (savedSplitStart <= *lastSplit && *lastSplit <= savedSplitEnd)
193            *lastSplit = savedSplitStart;
194        }
195      }
196      isOpen=false ;
197
198      allDomainEmpty=true ;
199      set<CAxis*> setAxis;
200      set<CDomain*> setDomains;
201
202      std::vector<CField*>::iterator it, end = this->enabledFields.end();
203      for (it = this->enabledFields.begin(); it != end; it++)
204      {
205         CField* field = *it;
206         allDomainEmpty&=field->grid->domain->isEmpty();
207         setAxis.insert(field->grid->axis);
208         setDomains.insert(field->grid->domain);
209      }
210      nbAxis = setAxis.size();
211      nbDomains = setDomains.size();
212
213      // create sub communicator for file 
214      int color=allDomainEmpty?0:1 ;
215      MPI_Comm_split(server->intraComm,color,server->intraCommRank,&fileComm) ;
216      if (allDomainEmpty) MPI_Comm_free(&fileComm) ;
217
218      if (time_counter.isEmpty()) time_counter.setValue(time_counter_attr::centered);
219    }
220   
221    void CFile::checkFile(void)
222    {
223      if (!isOpen) createHeader() ;
224      checkSync() ;
225      checkSplit() ;
226    }
227     
228     
229   bool CFile::checkSync(void)
230   {
231     CContext* context = CContext::getCurrent() ;
232     CDate& currentDate=context->calendar->getCurrentDate() ;
233     if (! sync_freq.isEmpty())
234     {
235       if (*lastSync+syncFreq <= currentDate)
236       {
237         *lastSync=currentDate ;
238         data_out->syncFile() ;
239         return true ;
240        }
241      }
242      return false ;
243    }
244   
245   
246    bool CFile::checkSplit(void)
247    {
248      CContext* context = CContext::getCurrent() ;
249      CDate& currentDate=context->calendar->getCurrentDate() ;
250      if (! split_freq.isEmpty())
251      {
252        if (currentDate > *lastSplit+splitFreq)
253        {
254          *lastSplit=*lastSplit+splitFreq ;   
255          std::vector<CField*>::iterator it, end = this->enabledFields.end();
256          for (it = this->enabledFields.begin() ;it != end; it++)  (*it)->resetNStep() ;
257          createHeader() ;
258          return true ;
259        }
260      }
261      return false ;
262    }
263   
264   void CFile::createHeader(void)
265   {
266      CContext* context = CContext::getCurrent() ;
267      CContextServer* server=context->server ;
268     
269      if (!allDomainEmpty)
270      {
271         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
272         StdOStringStream oss;
273         oss << filename;
274         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
275//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStryyyymmdd()<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStryyyymmdd();
276//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStr("%y_%mo_%d")<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStr("%y_%mo_%d");
277         if (!split_freq.isEmpty())
278         {
279           CDate splitEnd = *lastSplit + splitFreq - 1 * Second;
280
281           string splitFormat ;
282           if (split_freq_format.isEmpty())
283           {
284             if (splitFreq.second!=0) splitFormat="%y%mo%d%h%mi%s";
285             else if (splitFreq.minute!=0) splitFormat="%y%mo%d%h%mi";
286             else if (splitFreq.hour!=0) splitFormat="%y%mo%d%h";
287             else if (splitFreq.day!=0) splitFormat="%y%mo%d";
288             else if (splitFreq.month!=0) splitFormat="%y%mo";
289             else splitFormat="%y";
290           }
291           else splitFormat=split_freq_format ;
292           oss<<"_"<<lastSplit->getStr(splitFormat)<<"-"<< splitEnd.getStr(splitFormat);
293
294           string lastSplitStr = lastSplit->toString(), splitEndStr = splitEnd.toString();
295           context->registryOut->setKey("splitStart", lastSplitStr);
296           context->registryOut->setKey("splitEnd",   splitEndStr);
297         }
298           
299         bool multifile=true ;
300         if (!type.isEmpty())
301         {
302           if (type==type_attr::one_file) multifile=false ;
303           else if (type==type_attr::multiple_file) multifile=true ;
304
305         } 
306#ifndef USING_NETCDF_PAR
307         if (!multifile)
308         {
309            info(0)<<"!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : "<<filename<<" ..."<<endl ;
310            multifile=true ;
311          }
312#endif
313         if (multifile) 
314         {
315            int commSize, commRank ;
316            MPI_Comm_size(fileComm,&commSize) ;
317            MPI_Comm_rank(fileComm,&commRank) ;
318           
319            if (server->intraCommSize > 1) 
320            {
321              oss << "_"  ;
322              int width=0 ; int n=commSize-1 ;
323              while(n != 0) { n=n/10 ; width++ ;}
324              if (!min_digits.isEmpty()) 
325                if (width<min_digits) width=min_digits ;
326              oss.width(width) ;
327              oss.fill('0') ;
328              oss<<right<< commRank;
329            }
330         }
331         oss << ".nc";
332
333        bool append = !this->append.isEmpty() && this->append.getValue();
334
335         if (isOpen) data_out->closeFile() ;
336         bool isCollective=true ;
337         if (!par_access.isEmpty())
338         {
339           if (par_access.getValue()=="independent") isCollective=false ;
340           else if (par_access.getValue()=="collective") isCollective=true ;
341           else 
342           {
343             ERROR("void Context::createDataOutput(void)",
344                        "incorrect file <par_access> attribut : must be <collective> or <indepedent>, "
345                        <<"having : <"<<type.getValue()<<">") ;
346           }
347         }
348        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), append, fileComm, multifile, isCollective));
349        isOpen = true;
350
351        data_out->writeFile(CFile::get(this));
352
353        // Do not recreate the file structure if opening an existing file
354        if (!data_out->IsInAppendMode())
355        {
356          std::vector<CField*>::iterator it, end = this->enabledFields.end();
357          for (it = this->enabledFields.begin(); it != end; it++)
358          {
359            CField* field = *it;
360            this->data_out->writeFieldGrid(field);
361          }
362          this->data_out->writeTimeDimension();
363
364          for (it = this->enabledFields.begin(); it != end; it++)
365          {
366            CField* field = *it;
367            this->data_out->writeField(field);
368          }
369
370          vector<CVariable*> listVars = getAllVariables() ;
371          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
372            this->data_out->writeAttribute(*it);
373
374          this->data_out->definition_end();
375        }
376      }
377   }
378
379   void CFile::close(void)
380   {
381     delete lastSync ;
382     delete lastSplit ;
383     if (!allDomainEmpty)
384       if (isOpen) 
385       {
386         this->data_out->closeFile();
387       }
388      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
389   }
390   //----------------------------------------------------------------
391
392   void CFile::parse(xml::CXMLNode & node)
393   {
394      SuperClass::parse(node);
395     
396      if (node.goToChildElement())
397      {
398        do
399        {
400           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
401           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
402        } while (node.goToNextElement()) ;
403        node.goToParentElement();
404      }
405
406   }
407   //----------------------------------------------------------------
408
409   StdString CFile::toString(void) const
410   {
411      StdOStringStream oss;
412
413      oss << "<" << CFile::GetName() << " ";
414      if (this->hasId())
415         oss << " id=\"" << this->getId() << "\" ";
416      oss << SuperClassAttribute::toString() << ">" << std::endl;
417      if (this->getVirtualFieldGroup() != NULL)
418         oss << *this->getVirtualFieldGroup() << std::endl;
419      oss << "</" << CFile::GetName() << " >";
420      return (oss.str());
421   }
422
423   //----------------------------------------------------------------
424   
425   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
426   {
427      SuperClassAttribute::setAttributes(parent,apply);
428      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL); 
429      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
430   }
431
432   //----------------------------------------------------------------
433
434   void CFile::processEnabledFile(void)
435   {
436     if (output_freq.isEmpty()) ERROR("void CFile::processEnabledFile(void)",
437                                       <<"File attribute <<output_freq>> is undefined"); 
438     solveFieldRefInheritance(true) ;
439     getEnabledFields() ;
440     processEnabledFields() ;
441   }
442   
443   void CFile::processEnabledFields(void)
444   {
445      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
446      {
447        this->enabledFields[i]->processEnabledField() ;
448      }
449    }
450   
451   void CFile::solveFieldRefInheritance(bool apply)
452   {
453      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
454      std::vector<CField*> allF = this->getAllFields();
455      for (unsigned int i = 0; i < allF.size(); i++)
456         allF[i]->solveRefInheritance(apply);
457   }
458
459   //----------------------------------------------------------------
460
461   void CFile::solveEFGridRef(void)
462   {
463      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
464         this->enabledFields[i]->solveGridReference();
465   }
466
467   //----------------------------------------------------------------
468
469   void CFile::solveEFOperation(void)
470   {
471      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
472         this->enabledFields[i]->solveOperation();
473   }
474 
475   void CFile::solveEFExpression(void)
476   {
477      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
478         this->enabledFields[i]->buildExpression();
479   }   
480 
481
482   CField* CFile::addField(const string& id)
483   {
484     return vFieldGroup->createChild(id) ;
485   }
486
487   CFieldGroup* CFile::addFieldGroup(const string& id)
488   {
489     return vFieldGroup->createChildGroup(id) ;
490   }
491 
492   CVariable* CFile::addVariable(const string& id)
493   {
494     return vVariableGroup->createChild(id) ;
495   }
496
497   CVariableGroup* CFile::addVariableGroup(const string& id)
498   {
499     return vVariableGroup->createChildGroup(id) ;
500   }
501   
502 
503   void CFile::sendAddField(const string& id)
504   {
505    CContext* context=CContext::getCurrent() ;
506   
507    if (! context->hasServer )
508    {
509       CContextClient* client=context->client ;
510
511       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;   
512       if (client->isServerLeader())
513       {
514         CMessage msg ;
515         msg<<this->getId() ;
516         msg<<id ;
517         event.push(client->getServerLeader(),1,msg) ;
518         client->sendEvent(event) ;
519       }
520       else client->sendEvent(event) ;
521    }
522     
523   }
524   
525   void CFile::sendAddFieldGroup(const string& id)
526   {
527    CContext* context=CContext::getCurrent() ;
528    if (! context->hasServer )
529    {
530       CContextClient* client=context->client ;
531
532       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;   
533       if (client->isServerLeader())
534       {
535         CMessage msg ;
536         msg<<this->getId() ;
537         msg<<id ;
538         event.push(client->getServerLeader(),1,msg) ;
539         client->sendEvent(event) ;
540       }
541       else client->sendEvent(event) ;
542    }
543     
544   }
545   
546   void CFile::recvAddField(CEventServer& event)
547   {
548     
549      CBufferIn* buffer=event.subEvents.begin()->buffer;
550      string id;
551      *buffer>>id ;
552      get(id)->recvAddField(*buffer) ;
553   }
554   
555   
556   void CFile::recvAddField(CBufferIn& buffer)
557   {
558      string id ;
559      buffer>>id ;
560      addField(id) ;
561   }
562
563   void CFile::recvAddFieldGroup(CEventServer& event)
564   {
565     
566      CBufferIn* buffer=event.subEvents.begin()->buffer;
567      string id;
568      *buffer>>id ;
569      get(id)->recvAddFieldGroup(*buffer) ;
570   }
571   
572   
573   void CFile::recvAddFieldGroup(CBufferIn& buffer)
574   {
575      string id ;
576      buffer>>id ;
577      addFieldGroup(id) ;
578   }
579   
580
581
582
583
584
585
586
587
588
589
590   void CFile::sendAddVariable(const string& id)
591   {
592    CContext* context=CContext::getCurrent() ;
593   
594    if (! context->hasServer )
595    {
596       CContextClient* client=context->client ;
597
598       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE) ;   
599       if (client->isServerLeader())
600       {
601         CMessage msg ;
602         msg<<this->getId() ;
603         msg<<id ;
604         event.push(client->getServerLeader(),1,msg) ;
605         client->sendEvent(event) ;
606       }
607       else client->sendEvent(event) ;
608    }
609     
610   }
611   
612   void CFile::sendAddVariableGroup(const string& id)
613   {
614    CContext* context=CContext::getCurrent() ;
615    if (! context->hasServer )
616    {
617       CContextClient* client=context->client ;
618
619       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP) ;   
620       if (client->isServerLeader())
621       {
622         CMessage msg ;
623         msg<<this->getId() ;
624         msg<<id ;
625         event.push(client->getServerLeader(),1,msg) ;
626         client->sendEvent(event) ;
627       }
628       else client->sendEvent(event) ;
629    }
630     
631   }
632   
633   void CFile::recvAddVariable(CEventServer& event)
634   {
635     
636      CBufferIn* buffer=event.subEvents.begin()->buffer;
637      string id;
638      *buffer>>id ;
639      get(id)->recvAddVariable(*buffer) ;
640   }
641   
642   
643   void CFile::recvAddVariable(CBufferIn& buffer)
644   {
645      string id ;
646      buffer>>id ;
647      addVariable(id) ;
648   }
649
650   void CFile::recvAddVariableGroup(CEventServer& event)
651   {
652     
653      CBufferIn* buffer=event.subEvents.begin()->buffer;
654      string id;
655      *buffer>>id ;
656      get(id)->recvAddVariableGroup(*buffer) ;
657   }
658   
659   
660   void CFile::recvAddVariableGroup(CBufferIn& buffer)
661   {
662      string id ;
663      buffer>>id ;
664      addVariableGroup(id) ;
665   }
666
667
668
669
670
671   bool CFile::dispatchEvent(CEventServer& event)
672   {
673      if (SuperClass::dispatchEvent(event)) return true ;
674      else
675      {
676        switch(event.type)
677        {
678           case EVENT_ID_ADD_FIELD :
679             recvAddField(event) ;
680             return true ;
681             break ;
682         
683           case EVENT_ID_ADD_FIELD_GROUP :
684             recvAddFieldGroup(event) ;
685             return true ;
686             break ;       
687 
688            case EVENT_ID_ADD_VARIABLE :
689             recvAddVariable(event) ;
690             return true ;
691             break ;
692         
693           case EVENT_ID_ADD_VARIABLE_GROUP :
694             recvAddVariableGroup(event) ;
695             return true ;
696             break ;               
697           default :
698              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
699           return false ;
700        }
701      }
702   }
703   
704   
705   
706   
707   ///---------------------------------------------------------------
708
709} // namespace xios
Note: See TracBrowser for help on using the repository browser.