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
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<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     
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   {
214     CContext* context = CContext::getCurrent() ;
215     CDate& currentDate=context->calendar->getCurrentDate() ;
216     if (! sync_freq.isEmpty())
217     {
218       if (*lastSync+syncFreq <= currentDate)
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    {
231      CContext* context = CContext::getCurrent() ;
232      CDate& currentDate=context->calendar->getCurrentDate() ;
233      if (! split_freq.isEmpty())
234      {
235        if (currentDate > *lastSplit+splitFreq)
236        {
237          *lastSplit=*lastSplit+splitFreq ;   
238          std::vector<CField*>::iterator it, end = this->enabledFields.end();
239          for (it = this->enabledFields.begin() ;it != end; it++)  (*it)->resetNStep() ;
240          createHeader() ;
241          return true ;
242        }
243      }
244      return false ;
245    }
246   
247   void CFile::createHeader(void)
248   {
249      CContext* context = CContext::getCurrent() ;
250      CContextServer* server=context->server ;
251     
252      if (!allDomainEmpty)
253      {
254         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
255         StdOStringStream oss;
256         oss << filename;
257         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
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           
276         bool multifile=true ;
277         if (!type.isEmpty())
278         {
279           if (type==type_attr::one_file) multifile=false ;
280           else if (type==type_attr::multiple_file) multifile=true ;
281
282         } 
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
290         if (multifile) 
291         {
292            int commSize, commRank ;
293            MPI_Comm_size(fileComm,&commSize) ;
294            MPI_Comm_rank(fileComm,&commRank) ;
295           
296            if (server->intraCommSize > 1) 
297            {
298              oss << "_"  ;
299              int width=0 ; int n=commSize-1 ;
300              while(n != 0) { n=n/10 ; width++ ;}
301              if (!min_digits.isEmpty()) 
302                if (width<min_digits) width=min_digits ;
303              oss.width(width) ;
304              oss.fill('0') ;
305              oss<<right<< commRank;
306            }
307         }
308         oss << ".nc";
309
310         if (isOpen) data_out->closeFile() ;
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         }
323         data_out=shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), false, fileComm, multifile, isCollective));
324         isOpen=true ;
325
326         data_out->writeFile(CFile::get(this));
327         std::vector<CField*>::iterator it, end = this->enabledFields.end();
328         for (it = this->enabledFields.begin() ;it != end; it++)
329         {
330            CField* field = *it;
331            this->data_out->writeFieldGrid(field);
332         }
333         this->data_out->writeTimeDimension();
334         
335         for (it = this->enabledFields.begin() ;it != end; it++)
336         {
337            CField* field = *it;
338            this->data_out->writeField(field);
339         }
340         
341         vector<CVariable*> listVars = getAllVariables() ;
342         for (vector<CVariable*>::iterator it = listVars.begin() ;it != listVars.end(); it++) this-> data_out-> writeAttribute(*it) ;
343         
344         this->data_out->definition_end();
345      }
346   }
347
348   void CFile::close(void)
349   {
350     delete lastSync ;
351     delete lastSplit ;
352     if (!allDomainEmpty)
353       if (isOpen) 
354       {
355         this->data_out->closeFile();
356       }
357      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
358   }
359   //----------------------------------------------------------------
360
361   void CFile::parse(xml::CXMLNode & node)
362   {
363      SuperClass::parse(node);
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();
373      }
374
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;
386      if (this->getVirtualFieldGroup() != NULL)
387         oss << *this->getVirtualFieldGroup() << std::endl;
388      oss << "</" << CFile::GetName() << " >";
389      return (oss.str());
390   }
391
392   //----------------------------------------------------------------
393   
394   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
395   {
396      SuperClassAttribute::setAttributes(parent,apply);
397      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL); 
398      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
399   }
400
401   //----------------------------------------------------------------
402
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   
420   void CFile::solveFieldRefInheritance(bool apply)
421   {
422      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
423      std::vector<CField*> allF = this->getAllFields();
424      for (unsigned int i = 0; i < allF.size(); i++)
425         allF[i]->solveRefInheritance(apply);
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   }
443 
444   void CFile::solveEFExpression(void)
445   {
446      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
447         this->enabledFields[i]->buildExpression();
448   }   
449 
450
451   CField* CFile::addField(const string& id)
452   {
453     return vFieldGroup->createChild(id) ;
454   }
455
456   CFieldGroup* CFile::addFieldGroup(const string& id)
457   {
458     return vFieldGroup->createChildGroup(id) ;
459   }
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   }
470   
471 
472   void CFile::sendAddField(const string& id)
473   {
474    CContext* context=CContext::getCurrent() ;
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   {
496    CContext* context=CContext::getCurrent() ;
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
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
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 ;       
656 
657            case EVENT_ID_ADD_VARIABLE :
658             recvAddVariable(event) ;
659             return true ;
660             break ;
661         
662           case EVENT_ID_ADD_VARIABLE_GROUP :
663             recvAddVariableGroup(event) ;
664             return true ;
665             break ;               
666           default :
667              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
668           return false ;
669        }
670      }
671   }
672   
673   
674   
675   
676   ///---------------------------------------------------------------
677
678} // namespace xios
Note: See TracBrowser for help on using the repository browser.