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

Last change on this file since 692 was 692, checked in by rlacroix, 7 years ago

Add a new file attribute to give our users more control on the time counter.

The time_counter attribute can take one of the following values:

  • centered: use centered times for the time counter (previous behavior, used by default)
  • instant: use instant times for the time counter
  • record: use record indexes for the time counter
  • none: disable the output of the time counter completely.
  • 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.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   { 
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         if (isOpen) data_out->closeFile() ;
314         bool isCollective=true ;
315         if (!par_access.isEmpty())
316         {
317           if (par_access.getValue()=="independent") isCollective=false ;
318           else if (par_access.getValue()=="collective") isCollective=true ;
319           else 
320           {
321             ERROR("void Context::createDataOutput(void)",
322                        "incorrect file <par_access> attribut : must be <collective> or <indepedent>, "
323                        <<"having : <"<<type.getValue()<<">") ;
324           }
325         }
326         data_out=shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), false, fileComm, multifile, isCollective));
327         isOpen=true ;
328
329         data_out->writeFile(CFile::get(this));
330         std::vector<CField*>::iterator it, end = this->enabledFields.end();
331         for (it = this->enabledFields.begin() ;it != end; it++)
332         {
333            CField* field = *it;
334            this->data_out->writeFieldGrid(field);
335         }
336         this->data_out->writeTimeDimension();
337         
338         for (it = this->enabledFields.begin() ;it != end; it++)
339         {
340            CField* field = *it;
341            this->data_out->writeField(field);
342         }
343         
344         vector<CVariable*> listVars = getAllVariables() ;
345         for (vector<CVariable*>::iterator it = listVars.begin() ;it != listVars.end(); it++) this-> data_out-> writeAttribute(*it) ;
346         
347         this->data_out->definition_end();
348      }
349   }
350
351   void CFile::close(void)
352   {
353     delete lastSync ;
354     delete lastSplit ;
355     if (!allDomainEmpty)
356       if (isOpen) 
357       {
358         this->data_out->closeFile();
359       }
360      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
361   }
362   //----------------------------------------------------------------
363
364   void CFile::parse(xml::CXMLNode & node)
365   {
366      SuperClass::parse(node);
367     
368      if (node.goToChildElement())
369      {
370        do
371        {
372           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
373           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
374        } while (node.goToNextElement()) ;
375        node.goToParentElement();
376      }
377
378   }
379   //----------------------------------------------------------------
380
381   StdString CFile::toString(void) const
382   {
383      StdOStringStream oss;
384
385      oss << "<" << CFile::GetName() << " ";
386      if (this->hasId())
387         oss << " id=\"" << this->getId() << "\" ";
388      oss << SuperClassAttribute::toString() << ">" << std::endl;
389      if (this->getVirtualFieldGroup() != NULL)
390         oss << *this->getVirtualFieldGroup() << std::endl;
391      oss << "</" << CFile::GetName() << " >";
392      return (oss.str());
393   }
394
395   //----------------------------------------------------------------
396   
397   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
398   {
399      SuperClassAttribute::setAttributes(parent,apply);
400      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL); 
401      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
402   }
403
404   //----------------------------------------------------------------
405
406   void CFile::processEnabledFile(void)
407   {
408     if (output_freq.isEmpty()) ERROR("void CFile::processEnabledFile(void)",
409                                       <<"File attribute <<output_freq>> is undefined"); 
410     solveFieldRefInheritance(true) ;
411     getEnabledFields() ;
412     processEnabledFields() ;
413   }
414   
415   void CFile::processEnabledFields(void)
416   {
417      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
418      {
419        this->enabledFields[i]->processEnabledField() ;
420      }
421    }
422   
423   void CFile::solveFieldRefInheritance(bool apply)
424   {
425      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
426      std::vector<CField*> allF = this->getAllFields();
427      for (unsigned int i = 0; i < allF.size(); i++)
428         allF[i]->solveRefInheritance(apply);
429   }
430
431   //----------------------------------------------------------------
432
433   void CFile::solveEFGridRef(void)
434   {
435      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
436         this->enabledFields[i]->solveGridReference();
437   }
438
439   //----------------------------------------------------------------
440
441   void CFile::solveEFOperation(void)
442   {
443      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
444         this->enabledFields[i]->solveOperation();
445   }
446 
447   void CFile::solveEFExpression(void)
448   {
449      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
450         this->enabledFields[i]->buildExpression();
451   }   
452 
453
454   CField* CFile::addField(const string& id)
455   {
456     return vFieldGroup->createChild(id) ;
457   }
458
459   CFieldGroup* CFile::addFieldGroup(const string& id)
460   {
461     return vFieldGroup->createChildGroup(id) ;
462   }
463 
464   CVariable* CFile::addVariable(const string& id)
465   {
466     return vVariableGroup->createChild(id) ;
467   }
468
469   CVariableGroup* CFile::addVariableGroup(const string& id)
470   {
471     return vVariableGroup->createChildGroup(id) ;
472   }
473   
474 
475   void CFile::sendAddField(const string& id)
476   {
477    CContext* context=CContext::getCurrent() ;
478   
479    if (! context->hasServer )
480    {
481       CContextClient* client=context->client ;
482
483       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;   
484       if (client->isServerLeader())
485       {
486         CMessage msg ;
487         msg<<this->getId() ;
488         msg<<id ;
489         event.push(client->getServerLeader(),1,msg) ;
490         client->sendEvent(event) ;
491       }
492       else client->sendEvent(event) ;
493    }
494     
495   }
496   
497   void CFile::sendAddFieldGroup(const string& id)
498   {
499    CContext* context=CContext::getCurrent() ;
500    if (! context->hasServer )
501    {
502       CContextClient* client=context->client ;
503
504       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;   
505       if (client->isServerLeader())
506       {
507         CMessage msg ;
508         msg<<this->getId() ;
509         msg<<id ;
510         event.push(client->getServerLeader(),1,msg) ;
511         client->sendEvent(event) ;
512       }
513       else client->sendEvent(event) ;
514    }
515     
516   }
517   
518   void CFile::recvAddField(CEventServer& event)
519   {
520     
521      CBufferIn* buffer=event.subEvents.begin()->buffer;
522      string id;
523      *buffer>>id ;
524      get(id)->recvAddField(*buffer) ;
525   }
526   
527   
528   void CFile::recvAddField(CBufferIn& buffer)
529   {
530      string id ;
531      buffer>>id ;
532      addField(id) ;
533   }
534
535   void CFile::recvAddFieldGroup(CEventServer& event)
536   {
537     
538      CBufferIn* buffer=event.subEvents.begin()->buffer;
539      string id;
540      *buffer>>id ;
541      get(id)->recvAddFieldGroup(*buffer) ;
542   }
543   
544   
545   void CFile::recvAddFieldGroup(CBufferIn& buffer)
546   {
547      string id ;
548      buffer>>id ;
549      addFieldGroup(id) ;
550   }
551   
552
553
554
555
556
557
558
559
560
561
562   void CFile::sendAddVariable(const string& id)
563   {
564    CContext* context=CContext::getCurrent() ;
565   
566    if (! context->hasServer )
567    {
568       CContextClient* client=context->client ;
569
570       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE) ;   
571       if (client->isServerLeader())
572       {
573         CMessage msg ;
574         msg<<this->getId() ;
575         msg<<id ;
576         event.push(client->getServerLeader(),1,msg) ;
577         client->sendEvent(event) ;
578       }
579       else client->sendEvent(event) ;
580    }
581     
582   }
583   
584   void CFile::sendAddVariableGroup(const string& id)
585   {
586    CContext* context=CContext::getCurrent() ;
587    if (! context->hasServer )
588    {
589       CContextClient* client=context->client ;
590
591       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP) ;   
592       if (client->isServerLeader())
593       {
594         CMessage msg ;
595         msg<<this->getId() ;
596         msg<<id ;
597         event.push(client->getServerLeader(),1,msg) ;
598         client->sendEvent(event) ;
599       }
600       else client->sendEvent(event) ;
601    }
602     
603   }
604   
605   void CFile::recvAddVariable(CEventServer& event)
606   {
607     
608      CBufferIn* buffer=event.subEvents.begin()->buffer;
609      string id;
610      *buffer>>id ;
611      get(id)->recvAddVariable(*buffer) ;
612   }
613   
614   
615   void CFile::recvAddVariable(CBufferIn& buffer)
616   {
617      string id ;
618      buffer>>id ;
619      addVariable(id) ;
620   }
621
622   void CFile::recvAddVariableGroup(CEventServer& event)
623   {
624     
625      CBufferIn* buffer=event.subEvents.begin()->buffer;
626      string id;
627      *buffer>>id ;
628      get(id)->recvAddVariableGroup(*buffer) ;
629   }
630   
631   
632   void CFile::recvAddVariableGroup(CBufferIn& buffer)
633   {
634      string id ;
635      buffer>>id ;
636      addVariableGroup(id) ;
637   }
638
639
640
641
642
643   bool CFile::dispatchEvent(CEventServer& event)
644   {
645      if (SuperClass::dispatchEvent(event)) return true ;
646      else
647      {
648        switch(event.type)
649        {
650           case EVENT_ID_ADD_FIELD :
651             recvAddField(event) ;
652             return true ;
653             break ;
654         
655           case EVENT_ID_ADD_FIELD_GROUP :
656             recvAddFieldGroup(event) ;
657             return true ;
658             break ;       
659 
660            case EVENT_ID_ADD_VARIABLE :
661             recvAddVariable(event) ;
662             return true ;
663             break ;
664         
665           case EVENT_ID_ADD_VARIABLE_GROUP :
666             recvAddVariableGroup(event) ;
667             return true ;
668             break ;               
669           default :
670              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
671           return false ;
672        }
673      }
674   }
675   
676   
677   
678   
679   ///---------------------------------------------------------------
680
681} // namespace xios
Note: See TracBrowser for help on using the repository browser.