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

Last change on this file since 445 was 445, checked in by ymipsl, 11 years ago

Add possibility to make inheritance of attributes and reference before closing the context definition.
New fortran fonction : xios_solve inheritance()
After this call, the value of attribute have the inherited value of their parent.

YM

File size: 16.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   { setVirtualFieldGroup() ;}
27
28   CFile::CFile(const StdString & id)
29      : CObjectTemplate<CFile>(id), CFileAttributes()
30      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
31   { setVirtualFieldGroup() ;}
32
33   CFile::~CFile(void)
34   { /* Ne rien faire de plus */ }
35
36   ///---------------------------------------------------------------
37
38   StdString CFile::GetName(void)   { return (StdString("file")); }
39   StdString CFile::GetDefName(void){ return (CFile::GetName()); }
40   ENodeType CFile::GetType(void)   { return (eFile); }
41
42   //----------------------------------------------------------------
43
44   boost::shared_ptr<CDataOutput> CFile::getDataOutput(void) const
45   {
46      return (data_out);
47   }
48
49   CFieldGroup* CFile::getVirtualFieldGroup(void) const
50   {
51      return (this->vFieldGroup);
52   }
53
54   std::vector<CField*> CFile::getAllFields(void) const
55   {
56      return (this->vFieldGroup->getAllChildren());
57   }
58
59   //----------------------------------------------------------------
60
61   std::vector<CField*> CFile::getEnabledFields(int default_outputlevel, 
62                                                int default_level,
63                                                bool default_enabled)
64   {
65      if (!this->enabledFields.empty())
66         return (this->enabledFields);
67
68      const int _outputlevel =
69         (!output_level.isEmpty()) ? output_level.getValue() : default_outputlevel;
70      std::vector<CField*>::iterator it;
71      this->enabledFields = this->getAllFields();
72
73      std::vector<CField*> newEnabledFields;
74     
75      for ( it = this->enabledFields.begin() ; it != this->enabledFields.end(); it++ )
76      {
77         if (!(*it)->enabled.isEmpty()) // Si l'attribut 'enabled' est défini ...
78         {
79            if (! (*it)->enabled.getValue()) continue;
80//            { it--; this->enabledFields.erase(it+1); continue; }
81         }
82         else // Si l'attribut 'enabled' n'est pas défini ...
83         {
84            if (!default_enabled) continue ;
85//            { it--; this->enabledFields.erase(it+1); continue; }
86         }
87
88         if (!(*it)->level.isEmpty()) // Si l'attribut 'level' est défini ...
89         {
90            if ((*it)->level.getValue() > _outputlevel) continue ;
91//            { it--; this->enabledFields.erase(it+1); continue; }
92         }
93         else // Si l'attribut 'level' n'est pas défini ...
94         {
95            if (default_level > _outputlevel) continue ;
96//            { it--; this->enabledFields.erase(it+1); continue; }
97         }
98 
99//         CField* field_tmp=(*it).get() ;
100//         shared_ptr<CField> sptfield=*it ;
101//         field_tmp->refObject.push_back(sptfield) ;
102         newEnabledFields.push_back(*it) ;
103         // Le champ est finalement actif, on y ajoute sa propre reference.
104         (*it)->refObject.push_back(*it);
105         // Le champ est finalement actif, on y ajoute la référence au champ de base.
106         (*it)->setRelFile(CFile::get(this));
107         (*it)->baseRefObject->refObject.push_back(*it);
108         // A faire, ajouter les references intermediaires...
109      }
110      enabledFields=newEnabledFields ;
111
112      return (this->enabledFields);
113   }
114
115   //----------------------------------------------------------------
116
117   void CFile::setVirtualFieldGroup(CFieldGroup* newVFieldGroup)
118   { 
119      this->vFieldGroup = newVFieldGroup; 
120   }
121
122   //----------------------------------------------------------------
123
124   void CFile::setVirtualFieldGroup(void)
125   {
126      this->setVirtualFieldGroup(CFieldGroup::create());
127   }
128
129   //----------------------------------------------------------------
130   bool CFile::isSyncTime(void)
131   {
132     CContext* context = CContext::getCurrent() ;
133     CDate& currentDate=context->calendar->getCurrentDate() ;
134     if (! sync_freq.isEmpty())
135     {
136       if (*lastSync+syncFreq < currentDate)
137       {
138         *lastSync=currentDate ;
139         return true ;
140        }
141      }
142      return false ;
143    }
144   
145   void CFile::initFile(void)
146   {
147      CContext* context = CContext::getCurrent() ;
148      CDate& currentDate=context->calendar->getCurrentDate() ;
149      CContextServer* server=context->server ;
150           
151      if (! sync_freq.isEmpty()) syncFreq = CDuration::FromString(sync_freq.getValue());
152      if (! split_freq.isEmpty()) splitFreq = CDuration::FromString(split_freq.getValue());
153      if (! output_freq.isEmpty()) outputFreq = CDuration::FromString(output_freq.getValue());
154      lastSync=new CDate(currentDate) ;
155      lastSplit=new CDate(currentDate) ;
156      isOpen=false ;
157
158      allDomainEmpty=true ;
159      set<CDomain*> setDomain ;
160
161      std::vector<CField*>::iterator it, end = this->enabledFields.end();
162      for (it = this->enabledFields.begin() ;it != end; it++)
163      {
164         CField* field = *it;
165         allDomainEmpty&=field->grid->domain->isEmpty() ;
166         setDomain.insert(field->grid->domain) ;
167      }
168      nbDomain=setDomain.size() ;
169
170      // create sub communicator for file 
171      int color=allDomainEmpty?0:1 ;
172      MPI_Comm_split(server->intraComm,color,server->intraCommRank,&fileComm) ;
173      if (allDomainEmpty) MPI_Comm_free(&fileComm) ;
174      //
175     
176    }
177   
178    void CFile::checkFile(void)
179    {
180      if (!isOpen) createHeader() ;
181      checkSync() ;
182      checkSplit() ;
183    }
184     
185     
186   bool CFile::checkSync(void)
187   {
188     CContext* context = CContext::getCurrent() ;
189     CDate& currentDate=context->calendar->getCurrentDate() ;
190     if (! sync_freq.isEmpty())
191     {
192       if (*lastSync+syncFreq < currentDate)
193       {
194         *lastSync=currentDate ;
195         data_out->syncFile() ;
196         return true ;
197        }
198      }
199      return false ;
200    }
201   
202   
203    bool CFile::checkSplit(void)
204    {
205      CContext* context = CContext::getCurrent() ;
206      CDate& currentDate=context->calendar->getCurrentDate() ;
207      if (! split_freq.isEmpty())
208      {
209        if (currentDate > *lastSplit+splitFreq)
210        {
211          *lastSplit=*lastSplit+splitFreq ;   
212          std::vector<CField*>::iterator it, end = this->enabledFields.end();
213          for (it = this->enabledFields.begin() ;it != end; it++)  (*it)->resetNStep() ;
214          createHeader() ;
215          return true ;
216        }
217      }
218      return false ;
219    }
220   
221   void CFile::createHeader(void)
222   {
223      CContext* context = CContext::getCurrent() ;
224      CContextServer* server=context->server ;
225     
226      if (!allDomainEmpty)
227      {
228         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
229         StdOStringStream oss;
230         oss << filename;
231         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
232//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStryyyymmdd()<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStryyyymmdd();
233//         if (!split_freq.isEmpty()) oss<<"_"<<lastSplit->getStr("%y_%mo_%d")<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStr("%y_%mo_%d");
234         if (!split_freq.isEmpty())
235         {
236           string splitFormat ;
237           if (split_freq_format.isEmpty())
238           {
239             if (splitFreq.second!=0) splitFormat="%y%mo%d%h%mi%s";
240             else if (splitFreq.minute!=0) splitFormat="%y%mo%d%h%mi";
241             else if (splitFreq.hour!=0) splitFormat="%y%mo%d%h";
242             else if (splitFreq.day!=0) splitFormat="%y%mo%d";
243             else if (splitFreq.month!=0) splitFormat="%y%mo";
244             else splitFormat="%y";
245           }
246           else splitFormat=split_freq_format ;
247           oss<<"_"<<lastSplit->getStr(splitFormat)<<"-"<< (*lastSplit+(splitFreq-1*Second)).getStr(splitFormat);
248         }
249           
250         bool multifile=true ;
251         if (!type.isEmpty())
252         {
253           if (type==type_attr::one_file) multifile=false ;
254           else if (type==type_attr::multiple_file) multifile=true ;
255
256         } 
257#ifndef USING_NETCDF_PAR
258         if (!multifile)
259         {
260            info(0)<<"!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : "<<filename<<" ..."<<endl ;
261            multifile=true ;
262          }
263#endif
264         if (multifile) 
265         {
266            int commSize, commRank ;
267            MPI_Comm_size(fileComm,&commSize) ;
268            MPI_Comm_rank(fileComm,&commRank) ;
269           
270            if (server->intraCommSize > 1) 
271            {
272              oss << "_"  ;
273              int width=0 ; int n=commSize-1 ;
274              while(n != 0) { n=n/10 ; width++ ;}
275              if (!min_digits.isEmpty()) 
276                if (width<min_digits) width=min_digits ;
277              oss.width(width) ;
278              oss.fill('0') ;
279              oss<<right<< commRank;
280            }
281         }
282         oss << ".nc";
283
284         if (isOpen) data_out->closeFile() ;
285         bool isCollective=true ;
286         if (!par_access.isEmpty())
287         {
288           if (par_access.getValue()=="independent") isCollective=false ;
289           else if (par_access.getValue()=="collective") isCollective=true ;
290           else 
291           {
292             ERROR("void Context::createDataOutput(void)",
293                        "incorrect file <par_access> attribut : must be <collective> or <indepedent>, "
294                        <<"having : <"<<type.getValue()<<">") ;
295           }
296         }
297         data_out=shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), false, fileComm, multifile, isCollective));
298         isOpen=true ;
299
300         data_out->writeFile(CFile::get(this));
301         std::vector<CField*>::iterator it, end = this->enabledFields.end();
302         for (it = this->enabledFields.begin() ;it != end; it++)
303         {
304            CField* field = *it;
305            this->data_out->writeFieldGrid(field);
306         }
307         this->data_out->writeTimeDimension();
308         
309         for (it = this->enabledFields.begin() ;it != end; it++)
310         {
311            CField* field = *it;
312            this->data_out->writeField(field);
313         }
314         
315         this->data_out->definition_end();
316      }
317   }
318
319   void CFile::close(void)
320   {
321     delete lastSync ;
322     delete lastSplit ;
323     if (!allDomainEmpty)
324       if (isOpen) 
325       {
326         this->data_out->closeFile();
327       }
328      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
329   }
330   //----------------------------------------------------------------
331
332   void CFile::parse(xml::CXMLNode & node)
333   {
334      SuperClass::parse(node);
335      if (node.goToChildElement() & this->hasId())
336      { // Si la définition du fichier intégre des champs et si le fichier est identifié.
337         node.goToParentElement();
338//         this->setVirtualFieldGroup(this->getId());
339         this->getVirtualFieldGroup()->parse(node, false);
340      }
341   }
342   //----------------------------------------------------------------
343
344   StdString CFile::toString(void) const
345   {
346      StdOStringStream oss;
347
348      oss << "<" << CFile::GetName() << " ";
349      if (this->hasId())
350         oss << " id=\"" << this->getId() << "\" ";
351      oss << SuperClassAttribute::toString() << ">" << std::endl;
352      if (this->getVirtualFieldGroup() != NULL)
353         oss << *this->getVirtualFieldGroup() << std::endl;
354      oss << "</" << CFile::GetName() << " >";
355      return (oss.str());
356   }
357
358   //----------------------------------------------------------------
359   
360   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
361   {
362      SuperClassAttribute::setAttributes(parent,apply);
363      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
364   }
365
366   //----------------------------------------------------------------
367
368   void CFile::solveFieldRefInheritance(bool apply)
369   {
370      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
371      std::vector<CField*> allF = this->getAllFields();
372      for (unsigned int i = 0; i < allF.size(); i++)
373         allF[i]->solveRefInheritance(apply);
374   }
375
376   //----------------------------------------------------------------
377
378   void CFile::solveEFGridRef(void)
379   {
380      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
381         this->enabledFields[i]->solveGridReference();
382   }
383
384   //----------------------------------------------------------------
385
386   void CFile::solveEFOperation(void)
387   {
388      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
389         this->enabledFields[i]->solveOperation();
390   }
391   
392   //---------------------------------------------------------------
393/*
394   void CFile::toBinary  (StdOStream & os) const
395   {
396      ENodeType genum = CFileGroup::GetType();
397      bool hasVFG = (this->getVirtualFieldGroup() != NULL);
398      SuperClass::toBinary(os);
399     
400      os.write (reinterpret_cast<const char*>(&genum) , sizeof(ENodeType));
401      os.write (reinterpret_cast<const char*>(&hasVFG) , sizeof(bool));
402     
403      if (hasVFG)this->getVirtualFieldGroup()->toBinary(os);
404         
405   }
406   
407   //----------------------------------------------------------------
408   
409   void CFile::fromBinary(StdIStream & is)
410   {
411      ENodeType renum = Unknown;
412      bool hasVFG = false;
413      SuperClass::fromBinary(is);
414     
415      is.read (reinterpret_cast<char*>(&renum), sizeof(ENodeType));
416      is.read (reinterpret_cast<char*>(&hasVFG), sizeof(bool));
417     
418      if (renum != CFileGroup::GetType())
419         ERROR("CFile::fromBinary(StdIStream & is)",
420               << "[ renum = " << renum << "] Bad type !");
421     
422//      this->setVirtualFieldGroup(this->getId());
423      if (hasVFG)this->getVirtualFieldGroup()->fromBinary(is);
424     
425   }
426*/
427
428   CField* CFile::addField(const string& id)
429   {
430     return vFieldGroup->createChild(id) ;
431   }
432
433   CFieldGroup* CFile::addFieldGroup(const string& id)
434   {
435     return vFieldGroup->createChildGroup(id) ;
436   }
437   
438 
439   void CFile::sendAddField(const string& id)
440   {
441    CContext* context=CContext::getCurrent() ;
442   
443    if (! context->hasServer )
444    {
445       CContextClient* client=context->client ;
446
447       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;   
448       if (client->isServerLeader())
449       {
450         CMessage msg ;
451         msg<<this->getId() ;
452         msg<<id ;
453         event.push(client->getServerLeader(),1,msg) ;
454         client->sendEvent(event) ;
455       }
456       else client->sendEvent(event) ;
457    }
458     
459   }
460   
461   void CFile::sendAddFieldGroup(const string& id)
462   {
463    CContext* context=CContext::getCurrent() ;
464    if (! context->hasServer )
465    {
466       CContextClient* client=context->client ;
467
468       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;   
469       if (client->isServerLeader())
470       {
471         CMessage msg ;
472         msg<<this->getId() ;
473         msg<<id ;
474         event.push(client->getServerLeader(),1,msg) ;
475         client->sendEvent(event) ;
476       }
477       else client->sendEvent(event) ;
478    }
479     
480   }
481   
482   void CFile::recvAddField(CEventServer& event)
483   {
484     
485      CBufferIn* buffer=event.subEvents.begin()->buffer;
486      string id;
487      *buffer>>id ;
488      get(id)->recvAddField(*buffer) ;
489   }
490   
491   
492   void CFile::recvAddField(CBufferIn& buffer)
493   {
494      string id ;
495      buffer>>id ;
496      addField(id) ;
497   }
498
499   void CFile::recvAddFieldGroup(CEventServer& event)
500   {
501     
502      CBufferIn* buffer=event.subEvents.begin()->buffer;
503      string id;
504      *buffer>>id ;
505      get(id)->recvAddFieldGroup(*buffer) ;
506   }
507   
508   
509   void CFile::recvAddFieldGroup(CBufferIn& buffer)
510   {
511      string id ;
512      buffer>>id ;
513      addFieldGroup(id) ;
514   }
515   
516
517   bool CFile::dispatchEvent(CEventServer& event)
518   {
519      if (SuperClass::dispatchEvent(event)) return true ;
520      else
521      {
522        switch(event.type)
523        {
524           case EVENT_ID_ADD_FIELD :
525             recvAddField(event) ;
526             return true ;
527             break ;
528         
529           case EVENT_ID_ADD_FIELD_GROUP :
530             recvAddFieldGroup(event) ;
531             return true ;
532             break ;       
533         
534           default :
535              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
536           return false ;
537        }
538      }
539   }
540   
541   
542   
543   
544   ///---------------------------------------------------------------
545
546} // namespace xios
Note: See TracBrowser for help on using the repository browser.