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

Last change on this file since 472 was 472, checked in by ymipsl, 10 years ago

Enhancement : user defined global and field attribute can be output in the netcdfcf file.
A variable child element inclosed into a file element will be output as a global file attribute.
A variable child element inclosed into a field element will be output as a field attribute.

+ variable fortran interface added

YM

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