source: XIOS/dev/XIOS_DEV_CMIP6/src/node/file.cpp @ 1234

Last change on this file since 1234 was 1234, checked in by oabramkina, 7 years ago

Minor modifications for secondary server:

  • adding a check of the number of processes requested for the secondary server
  • making process distribution between two server levels in case of oasis similar to that wihtout oasis.
  • 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: 38.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 "context.hpp"
8#include "context_server.hpp"
9#include "nc4_data_output.hpp"
10#include "nc4_data_input.hpp"
11#include "calendar_util.hpp"
12#include "date.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "context_client.hpp"
17#include "mpi.hpp"
18#include "timer.hpp"
19#include "server.hpp"
20
21namespace xios {
22
23   /// ////////////////////// Dfinitions ////////////////////// ///
24
25   CFile::CFile(void)
26      : CObjectTemplate<CFile>(), CFileAttributes()
27      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
28      , isOpen(false), read_client(0), checkRead(false), allZoneEmpty(false)
29   {
30     setVirtualFieldGroup(CFieldGroup::create(getId() + "_virtual_field_group"));
31     setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group"));
32   }
33
34   CFile::CFile(const StdString & id)
35      : CObjectTemplate<CFile>(id), CFileAttributes()
36      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
37      , isOpen(false), read_client(0), checkRead(false), allZoneEmpty(false)
38    {
39      setVirtualFieldGroup(CFieldGroup::create(getId() + "_virtual_field_group"));
40      setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group"));
41    }
42
43   CFile::~CFile(void)
44   { /* Ne rien faire de plus */ }
45
46   ///---------------------------------------------------------------
47  //! Get name of file
48   StdString CFile::GetName(void)   { return (StdString("file")); }
49   StdString CFile::GetDefName(void){ return (CFile::GetName()); }
50   ENodeType CFile::GetType(void)   { return (eFile); }
51
52   //----------------------------------------------------------------
53
54   const StdString CFile::getFileOutputName(void) const
55   {
56     return (name.isEmpty() ? getId() : name) + (name_suffix.isEmpty() ? StdString("") :  name_suffix.getValue());
57   }
58
59   //----------------------------------------------------------------
60   /*!
61   \brief Get data writer object.
62   Each enabled file in xml represents a physical netcdf file.
63   This function allows to access the data writer object.
64   \return data writer object.
65   */
66   boost::shared_ptr<CDataOutput> CFile::getDataOutput(void) const
67   {
68      return data_out;
69   }
70
71   /*!
72   \brief Get data reader object.
73   Each enabled file in xml represents a physical netcdf file.
74   This function allows to access the data reader object.
75   \return data reader object.
76   */
77   boost::shared_ptr<CDataInput> CFile::getDataInput(void) const
78   {
79      return data_in;
80   }
81
82   /*!
83   \brief Get virtual field group
84      In each file, there always exists a field group which is the ancestor of all
85   fields in the file. This is considered be virtual because it is created automatically during
86   file initialization and it normally doesn't appear on xml file
87   \return Pointer to field group
88   */
89   CFieldGroup* CFile::getVirtualFieldGroup(void) const
90   {
91      return (this->vFieldGroup);
92   }
93
94   /*!
95   \brief Get virtual variable group
96      In each file, there always exists a variable group which is the ancestor of all
97   variable in the file. This is considered be virtual because it is created automatically during
98   file initialization and it normally doesn't appear on xml file
99   \return Pointer to variable group
100   */
101   CVariableGroup* CFile::getVirtualVariableGroup(void) const
102   {
103      return (this->vVariableGroup);
104   }
105
106   //! Get all fields of a file
107   std::vector<CField*> CFile::getAllFields(void) const
108   {
109      return (this->vFieldGroup->getAllChildren());
110   }
111
112   //! Get all variables of a file
113   std::vector<CVariable*> CFile::getAllVariables(void) const
114   {
115      return (this->vVariableGroup->getAllChildren());
116   }
117
118   //----------------------------------------------------------------
119   /*!
120   \brief Get all enabled fields of file
121      A field is considered to be enabled if it fullfil these conditions: it is enabled, inside a enabled file
122   and its own level is not larger than file output level.
123   \param [in] default_outputlevel default value output level of file
124   \param [in] default_level default value level of field
125   \param [in] default_enabled flag determine by default if field is enabled
126   \return Vector of pointers of enabled fields
127   */
128   std::vector<CField*> CFile::getEnabledFields(int default_outputlevel,
129                                                int default_level,
130                                                bool default_enabled)
131   {
132      if (!this->enabledFields.empty())
133         return (this->enabledFields);
134
135      const int _outputlevel =
136         (!output_level.isEmpty()) ? output_level.getValue() : default_outputlevel;
137      std::vector<CField*>::iterator it;
138      this->enabledFields = this->getAllFields();
139
140      std::vector<CField*> newEnabledFields;
141
142      for ( it = this->enabledFields.begin(); it != this->enabledFields.end(); it++ )
143      {
144         if (!(*it)->enabled.isEmpty()) // Si l'attribut 'enabled' est dfini ...
145         {
146            if (! (*it)->enabled.getValue()) continue;
147//            { it--; this->enabledFields.erase(it+1); continue; }
148         }
149         else // Si l'attribut 'enabled' n'est pas dfini ...
150         {
151            if (!default_enabled) continue;
152//            { it--; this->enabledFields.erase(it+1); continue; }
153         }
154
155         if (!(*it)->level.isEmpty()) // Si l'attribut 'level' est dfini ...
156         {
157            if ((*it)->level.getValue() > _outputlevel) continue;
158//            { it--; this->enabledFields.erase(it+1); continue; }
159         }
160         else // Si l'attribut 'level' n'est pas dfini ...
161         {
162            if (default_level > _outputlevel) continue;
163//            { it--; this->enabledFields.erase(it+1); continue; }
164         }
165
166//         CField* field_tmp=(*it).get();
167//         shared_ptr<CField> sptfield=*it;
168//         field_tmp->refObject.push_back(sptfield);
169         newEnabledFields.push_back(*it);
170         // Le champ est finalement actif, on y ajoute sa propre reference.
171//         (*it)->refObject.push_back(*it);
172         // Le champ est finalement actif, on y ajoute la rfrence au champ de base.
173         (*it)->setRelFile(CFile::get(this));
174      }
175      enabledFields = newEnabledFields;
176
177      return (this->enabledFields);
178   }
179
180   //----------------------------------------------------------------
181   //! Change virtual field group to a new one
182   void CFile::setVirtualFieldGroup(CFieldGroup* newVFieldGroup)
183   {
184      this->vFieldGroup = newVFieldGroup;
185   }
186
187   //! Change virtual variable group to new one
188   void CFile::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
189   {
190      this->vVariableGroup = newVVariableGroup;
191   }
192
193   //----------------------------------------------------------------
194   bool CFile::isSyncTime(void)
195   {
196     CContext* context = CContext::getCurrent();
197     const CDate& currentDate = context->calendar->getCurrentDate();
198     if (!sync_freq.isEmpty())
199     {
200       if (lastSync + sync_freq.getValue() < currentDate)
201       {
202         lastSync = currentDate;
203         return true;
204        }
205      }
206      return false;
207    }
208
209   //! Initialize a file in order to write into it
210   void CFile::initWrite(void)
211   {
212      CContext* context = CContext::getCurrent();
213      const CDate& currentDate = context->calendar->getCurrentDate();
214      CContextServer* server = context->server;
215
216      lastSync  = currentDate;
217      lastSplit = currentDate;
218      if (!split_freq.isEmpty())
219      {
220        StdString keySuffix("CContext_"+CContext::getCurrent()->getId()+"::CFile_"+getFileOutputName()+"::") ; 
221        if (context->registryIn->foundKey(keySuffix+"splitStart") && context->registryIn->foundKey(keySuffix+"splitEnd"))
222        {
223          CDate savedSplitStart(*context->getCalendar()), savedSplitEnd(*context->getCalendar());
224          context->registryIn->getKey(keySuffix+"splitStart", savedSplitStart);
225          context->registryIn->getKey(keySuffix+"splitEnd",   savedSplitEnd);
226
227          if (savedSplitStart <= lastSplit && lastSplit <= savedSplitEnd)
228            lastSplit = savedSplitStart;
229        }
230      }
231      isOpen = false;     
232
233//      if (!record_offset.isEmpty() && record_offset < 0)
234//        ERROR("void CFile::initFile(void)",
235//              "Invalid 'record_offset', this attribute cannot be negative.");
236      const int recordOffset = record_offset.isEmpty() ? 0 : record_offset;
237
238      set<StdString> setAxis;
239      set<StdString> setDomains;
240
241      std::vector<CField*>::iterator it, end = this->enabledFields.end();
242      for (it = this->enabledFields.begin(); it != end; it++)
243      {
244         CField* field = *it;         
245         std::vector<CAxis*> vecAxis = field->grid->getAxis();
246         for (size_t i = 0; i < vecAxis.size(); ++i)
247           setAxis.insert(vecAxis[i]->getAxisOutputName());
248         std::vector<CDomain*> vecDomains = field->grid->getDomains();
249         for (size_t i = 0; i < vecDomains.size(); ++i)
250           setDomains.insert(vecDomains[i]->getDomainOutputName());
251
252         field->resetNStep(recordOffset);
253      }
254      nbAxis = setAxis.size();
255      nbDomains = setDomains.size();
256
257      // create sub communicator for file
258      createSubComFile();
259
260      // if (time_counter.isEmpty()) time_counter.setValue(time_counter_attr::centered);
261      if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
262    }
263
264    //! Initialize a file in order to write into it
265    void CFile::initRead(void)
266    {
267      if (checkRead) return;
268      createSubComFile();
269      checkRead = true;
270    }
271
272    /*!
273      Create a sub communicator in which processes participate in reading/opening file
274    */
275    void CFile::createSubComFile()
276    {
277      CContext* context = CContext::getCurrent();
278      CContextServer* server = context->server;
279
280      // create sub communicator for file
281      allZoneEmpty = true;     
282      std::vector<CField*>::iterator it, end = this->enabledFields.end();
283      for (it = this->enabledFields.begin(); it != end; it++)
284      {
285         CField* field = *it;
286         bool nullGrid = (0 == field->grid);
287         allZoneEmpty &= nullGrid ? false : !field->grid->doGridHaveDataToWrite();
288      }
289
290      int color = allZoneEmpty ? 0 : 1;
291      MPI_Comm_split(server->intraComm, color, server->intraCommRank, &fileComm);
292      if (allZoneEmpty) MPI_Comm_free(&fileComm);
293    }
294
295    /*
296       Check condition to write into a file
297       For now, we only use the level-2 server to write files (if this mode is activated)
298       or classical server to do this job.
299    */
300    void CFile::checkWriteFile(void)
301    {
302      CContext* context = CContext::getCurrent();
303      // Done by classical server or secondary server
304      // This condition should be changed soon
305      if (CServer::serverLevel == 0 || CServer::serverLevel == 2)
306      {
307        if (mode.isEmpty() || mode.getValue() == mode_attr::write)
308        {
309          CTimer::get("Files : create headers").resume();
310          if (!isOpen) createHeader();
311          CTimer::get("Files : create headers").suspend();
312          checkSync();
313        }       
314        checkSplit(); // REally need this?
315      }
316    }
317
318    /*
319       Check condition to read from a file
320       For now, we only use the level-1 server to write files (if this mode is activated)
321       or classical server to do this job.
322       This function can be used by client for reading metadata
323    */
324    void CFile::checkReadFile(void)
325    {
326      CContext* context = CContext::getCurrent();
327      // Done by classical server or secondary server
328      // TODO: This condition should be changed soon. It only works with maximum number of level as 2
329      if (CServer::serverLevel == 0 || CServer::serverLevel == 2)
330      {
331        if (!mode.isEmpty() && mode.getValue() == mode_attr::read)
332        {
333          CTimer::get("Files : open headers").resume();
334         
335          if (!isOpen) openInReadMode();
336
337          CTimer::get("Files : open headers").suspend();
338        }
339        //checkSplit(); // Really need for reading?
340      }
341    }
342
343    /*!
344      Verify if a process participates in an opening-file communicator
345      \return true if the process doesn't participate in opening file
346    */
347    bool CFile::isEmptyZone()
348    {
349      return allZoneEmpty;
350    }
351
352    /*!
353    \brief Verify if synchronisation should be done
354        If syn option is enabled, syn frequence and current time will be used to
355    calculate the moment to syn file(s)
356    \return True if it is the moment to synchronize file, otherwise false
357    */
358   bool CFile::checkSync(void)
359   {
360     CContext* context = CContext::getCurrent();
361     const CDate& currentDate = context->calendar->getCurrentDate();
362     if (!sync_freq.isEmpty())
363     {
364       if (lastSync + sync_freq.getValue() <= currentDate)
365       {
366         lastSync = currentDate;
367         data_out->syncFile();
368         return true;
369        }
370      }
371      return false;
372    }
373
374    /*!
375    \brief Verify if splitting should be done
376        If split option is enabled, split frequence and current time will be used to
377    calculate the moment to split file
378    \return True if it is the moment to split file, otherwise false
379    */
380    bool CFile::checkSplit(void)
381    {
382      CContext* context = CContext::getCurrent();
383      const CDate& currentDate = context->calendar->getCurrentDate();
384      if (!split_freq.isEmpty())
385      {
386        if (currentDate > lastSplit + split_freq.getValue())
387        {
388          lastSplit = lastSplit + split_freq.getValue();
389          std::vector<CField*>::iterator it, end = this->enabledFields.end();
390          for (it = this->enabledFields.begin(); it != end; it++)
391          {
392            (*it)->resetNStep();
393            (*it)->resetNStepMax();
394          }
395          if (mode.isEmpty() || mode.getValue() == mode_attr::write)
396            createHeader();
397          else
398            openInReadMode();
399          return true;
400        }
401      }
402      return false;
403    }
404
405   /*!
406   \brief Create header of netcdf file
407   There are some information to fill in header of each netcdf.
408   */
409   void CFile::createHeader(void)
410   {
411      CContext* context = CContext::getCurrent();
412      CContextServer* server = context->server;
413
414      if (!allZoneEmpty)
415      {
416         StdString filename = getFileOutputName();
417
418// determine splitting format in the file name  : firstPart%start_date%middlePart%end_date%lastPart
419
420         std::string strStartDate="%start_date%" ;
421         std::string strEndDate="%end_date%" ;
422
423         std::string firstPart ;
424         std::string middlePart ;
425         std::string lastPart ;
426         size_t pos1, pos2 ;
427         bool hasStartDate=false ;
428         bool hasEndDate=false ;
429         bool hasSplit = (!split_freq.isEmpty());
430                 
431         pos1=filename.find(strStartDate) ;
432         if (pos1!=std::string::npos)
433         {
434           firstPart=filename.substr(0,pos1) ;
435           pos1+=strStartDate.size() ;
436           hasStartDate=true ;
437         }
438         else pos1=0 ;
439
440         pos2=filename.find(strEndDate,pos1) ;
441         if (pos2!=std::string::npos)
442         {
443           middlePart=filename.substr(pos1,pos2-pos1) ;
444           pos2+=strEndDate.size() ;
445           lastPart=filename.substr(pos2,filename.size()-pos2) ;
446           hasEndDate=true ;
447         }
448         else middlePart=filename.substr(pos1,filename.size()) ;
449
450         if (!hasStartDate && !hasEndDate)
451         {
452           hasStartDate=true ;
453           hasEndDate=true;
454           firstPart=middlePart ;
455           if (hasSplit) firstPart +="_";
456           middlePart="-" ;
457         }
458   
459         StdOStringStream oss;
460
461         if (!split_freq.isEmpty())
462         {
463           CDate split_start ;
464           CDate splitEnd ;
465           if (!split_start_offset.isEmpty()) split_start=lastSplit + split_start_offset ;
466           else split_start=lastSplit ;
467
468           splitEnd = lastSplit + split_freq ;
469           if (!split_last_date.isEmpty())
470           {
471             CDate splitLastDate=CDate::FromString(split_last_date,*CContext::getCurrent()->getCalendar()) ;
472             if( splitLastDate < splitEnd)  splitEnd=splitLastDate ;
473           }
474           
475           if (!split_end_offset.isEmpty()) splitEnd = splitEnd + split_end_offset;
476           else splitEnd = splitEnd - 1 * Second;
477
478           string splitFormat;
479           if (split_freq_format.isEmpty())
480           {
481             if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
482             else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
483             else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
484             else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
485             else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
486             else splitFormat = "%y";
487           }
488           else splitFormat = split_freq_format;
489
490           oss << firstPart ;
491           if (hasStartDate) oss << split_start.getStr(splitFormat) ;
492           oss << middlePart ;
493           if (hasEndDate) oss << splitEnd.getStr(splitFormat);
494           oss << lastPart ;
495
496           StdString keySuffix("CContext_"+CContext::getCurrent()->getId()+"::CFile_"+getFileOutputName()+"::") ; 
497           context->registryOut->setKey(keySuffix+"splitStart", lastSplit);
498           context->registryOut->setKey(keySuffix+"splitEnd",   splitEnd);
499         }
500         else oss<<firstPart<<lastPart ;
501
502        bool append = !this->append.isEmpty() && this->append.getValue();
503
504         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
505         bool useCFConvention = convention.isEmpty() || convention == convention_attr::CF;
506
507         bool multifile = true;
508         if (!type.isEmpty())
509         {
510           if (type == type_attr::one_file) multifile = false;
511           else if (type == type_attr::multiple_file) multifile = true;
512
513         }
514#ifndef USING_NETCDF_PAR
515         if (!multifile)
516         {
517            info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
518            multifile = true;
519          }
520#endif
521         if (multifile)
522         {
523            int commSize, commRank;
524            MPI_Comm_size(fileComm, &commSize);
525            MPI_Comm_rank(fileComm, &commRank);
526
527            if (server->intraCommSize > 1)
528            {
529              oss << "_" ;
530              int width=0; int n = commSize-1;
531              while (n != 0) { n = n / 10; width++;}
532              if (!min_digits.isEmpty())
533                if (width < min_digits) width = min_digits;
534              oss.width(width);
535              oss.fill('0');
536              oss << right << commRank;
537            }
538         }
539         oss << ".nc";
540
541         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
542
543         if (isOpen) data_out->closeFile();
544
545        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(this, oss.str(), append, useClassicFormat, useCFConvention,
546                                                              fileComm, multifile, isCollective, time_counter_name));
547        isOpen = true;
548
549        data_out->writeFile(CFile::get(this));
550
551        // Do not recreate the file structure if opening an existing file
552        if (!data_out->IsInAppendMode())
553        {
554          std::vector<CField*>::iterator it, end = this->enabledFields.end();
555          for (it = this->enabledFields.begin(); it != end; it++)
556          {
557            CField* field = *it;
558            this->data_out->writeFieldGrid(field);
559          }
560          this->data_out->writeTimeDimension();
561
562          for (it = this->enabledFields.begin(); it != end; it++)
563          {
564            CField* field = *it;
565            this->data_out->writeFieldTimeAxis(field);
566          }
567         
568          for (it = this->enabledFields.begin(); it != end; it++)
569          {
570            CField* field = *it;
571            this->data_out->writeField(field);
572          }
573
574          vector<CVariable*> listVars = getAllVariables();
575          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
576            this->data_out->writeAttribute(*it);
577
578          this->data_out->definition_end();
579        }
580        else
581        {
582          // check time axis even in append mode
583          std::vector<CField*>::iterator it, end = this->enabledFields.end();
584          for (it = this->enabledFields.begin(); it != end; it++)
585          {
586            CField* field = *it;
587            this->data_out->writeFieldTimeAxis(field);
588          }
589        }
590      }
591   }
592
593  /*!
594  \brief Open an existing NetCDF file in read-only mode
595  */
596  void CFile::openInReadMode()
597  {
598    CContext* context = CContext::getCurrent();
599    CContextServer* server = context->server;
600    MPI_Comm readComm = this->fileComm;
601
602    if (!allZoneEmpty)
603    {
604      StdString filename = getFileOutputName();
605      StdOStringStream oss;
606      oss << filename;
607
608      if (!split_freq.isEmpty())
609      {
610        string splitFormat;
611        if (split_freq_format.isEmpty())
612        {
613          if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
614          else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
615          else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
616          else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
617          else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
618          else splitFormat = "%y";
619        }
620        else splitFormat = split_freq_format;
621        oss << "_" << lastSplit.getStr(splitFormat)
622        << "-" << (lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
623      }
624
625      bool multifile = true;
626      if (!type.isEmpty())
627      {
628        if (type == type_attr::one_file) multifile = false;
629        else if (type == type_attr::multiple_file) multifile = true;
630      }
631  #ifndef USING_NETCDF_PAR
632      if (!multifile)
633      {
634        info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
635        multifile = true;
636      }
637  #endif
638      if (multifile)
639      {
640        int commSize, commRank;
641        MPI_Comm_size(readComm, &commSize);
642        MPI_Comm_rank(readComm, &commRank);
643
644        if (server->intraCommSize > 1)
645        {
646          oss << "_";
647          int width = 0, n = commSize - 1;
648          while (n != 0) { n = n / 10; width++; }
649          if (!min_digits.isEmpty() && width < min_digits)
650            width = min_digits;
651          oss.width(width);
652          oss.fill('0');
653          oss << right << commRank;
654        }
655      }
656      oss << ".nc";
657
658      bool isCollective = par_access.isEmpty() || par_access == par_access_attr::collective;
659
660      if (isOpen) data_out->closeFile();
661      if (time_counter_name.isEmpty()) data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective));
662      else data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective, time_counter_name));
663      isOpen = true;
664    }
665  }
666
667   //! Close file
668   void CFile::close(void)
669   {
670     if (!allZoneEmpty)
671       if (isOpen)
672       {
673         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
674          this->data_out->closeFile();
675         else
676          this->data_in->closeFile();
677        isOpen = false;
678       }
679      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
680   }
681   //----------------------------------------------------------------
682
683   void CFile::readAttributesOfEnabledFieldsInReadMode()
684   {
685     if (enabledFields.empty()) return;
686
687     // Just check file and try to open it
688     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
689
690     checkReadFile();
691
692     for (int idx = 0; idx < enabledFields.size(); ++idx)
693     {
694        // First of all, find out which domain and axis associated with this field
695        enabledFields[idx]->solveGridReference();
696
697        // Read attributes of domain and axis from this file
698        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
699
700        // Now complete domain and axis associated with this field
701        enabledFields[idx]->solveGenerateGrid();
702
703        // Read necessary value from file
704        this->data_in->readFieldAttributesValues(enabledFields[idx]);
705
706        // Fill attributes for base reference
707        enabledFields[idx]->solveGridDomainAxisBaseRef();
708     }
709
710     // Now everything is ok, close it
711     close();
712   }
713
714
715   /*!
716   \brief Parse xml file and write information into file object
717   \param [in] node xmld node corresponding in xml file
718   */
719   void CFile::parse(xml::CXMLNode & node)
720   {
721      SuperClass::parse(node);
722
723      if (node.goToChildElement())
724      {
725        do
726        {
727           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
728           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
729        } while (node.goToNextElement());
730        node.goToParentElement();
731      }
732
733   }
734   //----------------------------------------------------------------
735
736   /*!
737   \brief Represent a file in form of string with all its info
738   \return String
739   */
740   StdString CFile::toString(void) const
741   {
742      StdOStringStream oss;
743
744      oss << "<" << CFile::GetName() << " ";
745      if (this->hasId())
746         oss << " id=\"" << this->getId() << "\" ";
747      oss << SuperClassAttribute::toString() << ">" << std::endl;
748      if (this->getVirtualFieldGroup() != NULL)
749         oss << *this->getVirtualFieldGroup() << std::endl;
750      oss << "</" << CFile::GetName() << " >";
751      return (oss.str());
752   }
753
754   //----------------------------------------------------------------
755
756   /*!
757   \brief Find all inheritace among objects in a file.
758   \param [in] apply (true) write attributes of parent into ones of child if they are empty
759                     (false) write attributes of parent into a new container of child
760   \param [in] parent
761   */
762   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
763   {
764      SuperClassAttribute::setAttributes(parent,apply);
765      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
766      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
767   }
768
769   //----------------------------------------------------------------
770
771   /*!
772   \brief Resolve all reference of active fields.
773      In order to know exactly which data each active field has, a search for all its
774   reference to find its parents or/and its base reference object must be done. Moreover
775   during this search, there are some information that can only be sent to server AFTER
776   all information of active fields are created on server side, e.g: checking mask or index
777   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
778   */
779   void CFile::solveOnlyRefOfEnabledFields(bool sendToServer)
780   {
781     int size = this->enabledFields.size();
782     for (int i = 0; i < size; ++i)
783     {
784       this->enabledFields[i]->solveOnlyReferenceEnabledField(sendToServer);
785     }
786   }
787
788   void CFile::checkGridOfEnabledFields()
789   { 
790     int size = this->enabledFields.size();
791     for (int i = 0; i < size; ++i)
792     {
793       this->enabledFields[i]->checkGridOfEnabledFields();
794     }
795   }
796
797   void CFile::sendGridOfEnabledFields()
798   { 
799     int size = this->enabledFields.size();
800     for (int i = 0; i < size; ++i)
801     {
802       this->enabledFields[i]->sendGridOfEnabledFields();
803     }
804   }
805
806   void CFile::generateNewTransformationGridDest()
807   {
808     int size = this->enabledFields.size();
809     for (int i = 0; i < size; ++i)
810     {
811       this->enabledFields[i]->generateNewTransformationGridDest();
812     }
813   }
814
815   /*!
816   \brief Resolve all reference of active fields.
817      In order to know exactly which data each active field has, a search for all its
818   reference to find its parents or/and its base reference object must be done. Moreover
819   during this search, there are some information that can only be sent to server AFTER
820   all information of active fields are created on server side, e.g: checking mask or index
821   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
822   */
823   void CFile::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
824   {
825     int size = this->enabledFields.size();
826     for (int i = 0; i < size; ++i)
827     {       
828      this->enabledFields[i]->solveAllEnabledFieldsAndTransform();
829     }
830   }
831
832   /*!
833    * Constructs the filter graph for each active field.
834    *
835    * \param gc the garbage collector to use when building the filter graph
836    */
837   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
838   {
839     int size = this->enabledFields.size();
840     for (int i = 0; i < size; ++i)
841     {
842       this->enabledFields[i]->buildFilterGraph(gc, true);
843     }
844   }
845
846   /*!
847     Prefetching the data for enabled fields read from file.
848   */
849   void CFile::prefetchEnabledReadModeFields(void)
850   {
851     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
852       return;
853
854     int size = this->enabledFields.size();
855     for (int i = 0; i < size; ++i)
856       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
857   }
858
859   /*!
860     Prefetching the data for enabled fields read from file whose data is out-of-date.
861   */
862   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
863   {
864     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
865       return;
866
867     int size = this->enabledFields.size();
868     for (int i = 0; i < size; ++i)
869       this->enabledFields[i]->sendReadDataRequestIfNeeded();
870   }
871
872   void CFile::solveFieldRefInheritance(bool apply)
873   {
874      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
875      std::vector<CField*> allF = this->getAllFields();
876      for (unsigned int i = 0; i < allF.size(); i++)
877         allF[i]->solveRefInheritance(apply);
878   }
879
880   //----------------------------------------------------------------
881
882   /*!
883   \brief Add a field into file.
884      A field is added into file and it will be written out if the file is enabled and
885   level of this field is smaller than level_output. A new field won't be created if one
886   with id has already existed
887   \param [in] id String identity of new field
888   \return Pointer to added (or already existed) field
889   */
890   CField* CFile::addField(const string& id)
891   {
892     return vFieldGroup->createChild(id);
893   }
894
895   /*!
896   \brief Add a field group into file.
897      A field group is added into file and it will play a role as parents for fields.
898   A new field group won't be created if one with id has already existed
899   \param [in] id String identity of new field group
900   \return Pointer to added (or already existed) field group
901   */
902   CFieldGroup* CFile::addFieldGroup(const string& id)
903   {
904     return vFieldGroup->createChildGroup(id);
905   }
906
907   /*!
908   \brief Add a variable into file.
909      A variable is added into file and if one with id has already existed, pointer to
910   it will be returned.
911      Variable as long as attributes are information container of file.
912   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
913   to fill in (extra) information for a file.
914   \param [in] id String identity of new variable
915   \return Pointer to added (or already existed) variable
916   */
917   CVariable* CFile::addVariable(const string& id)
918   {
919     return vVariableGroup->createChild(id);
920   }
921
922   /*!
923   \brief Add a variable group into file.
924      A variable group is added into file and it will play a role as parents for variables.
925   A new variable group won't be created if one with id has already existed
926   \param [in] id String identity of new variable group
927   \return Pointer to added (or already existed) variable group
928   */
929   CVariableGroup* CFile::addVariableGroup(const string& id)
930   {
931     return vVariableGroup->createChildGroup(id);
932   }
933
934   void CFile::setContextClient(CContextClient* newContextClient)
935   {
936     client = newContextClient;
937   }
938
939   CContextClient* CFile::getContextClient()
940   {
941     return client;
942   }
943
944   void CFile::setReadContextClient(CContextClient* readContextclient)
945   {
946     read_client = readContextclient;
947   }
948
949   CContextClient* CFile::getReadContextClient()
950   {
951     return read_client;
952   }
953
954   /*!
955   \brief Send a message to create a field on server side
956   \param[in] id String identity of field that will be created on server
957   */
958   void CFile::sendAddField(const string& id, CContextClient* client)
959   {
960      sendAddItem(id, EVENT_ID_ADD_FIELD, client);
961   }
962
963   /*!
964   \brief Send a message to create a field group on server side
965   \param[in] id String identity of field group that will be created on server
966   */
967   void CFile::sendAddFieldGroup(const string& id, CContextClient* client)
968   {
969      sendAddItem(id, (int)EVENT_ID_ADD_FIELD_GROUP, client);
970   }
971
972   /*!
973   \brief Receive a message annoucing the creation of a field on server side
974   \param[in] event Received event
975   */
976   void CFile::recvAddField(CEventServer& event)
977   {
978
979      CBufferIn* buffer = event.subEvents.begin()->buffer;
980      string id;
981      *buffer>>id;
982      get(id)->recvAddField(*buffer);
983   }
984
985   /*!
986   \brief Receive a message annoucing the creation of a field on server side
987   \param[in] buffer Buffer containing message
988   */
989   void CFile::recvAddField(CBufferIn& buffer)
990   {
991      string id;
992      buffer>>id;
993      addField(id);
994   }
995
996   /*!
997   \brief Receive a message annoucing the creation of a field group on server side
998   \param[in] event Received event
999   */
1000   void CFile::recvAddFieldGroup(CEventServer& event)
1001   {
1002
1003      CBufferIn* buffer = event.subEvents.begin()->buffer;
1004      string id;
1005      *buffer>>id;
1006      get(id)->recvAddFieldGroup(*buffer);
1007   }
1008
1009   /*!
1010   \brief Receive a message annoucing the creation of a field group on server side
1011   \param[in] buffer Buffer containing message
1012   */
1013   void CFile::recvAddFieldGroup(CBufferIn& buffer)
1014   {
1015      string id;
1016      buffer>>id;
1017      addFieldGroup(id);
1018   }
1019
1020   /*!
1021   \brief Send messages to duplicate all variables on server side
1022      Because each variable has also its attributes. So first thing to do is replicate
1023   all these attributes on server side. Because variable can have a value, the second thing
1024   is to duplicate this value on server, too.
1025   */
1026   void CFile::sendAddAllVariables(CContextClient* client)
1027   {
1028     std::vector<CVariable*> allVar = getAllVariables();
1029     std::vector<CVariable*>::const_iterator it = allVar.begin();
1030     std::vector<CVariable*>::const_iterator itE = allVar.end();
1031
1032     for (; it != itE; ++it)
1033     {
1034       this->sendAddVariable((*it)->getId(), client);
1035       (*it)->sendAllAttributesToServer(client);
1036       (*it)->sendValue(client);
1037     }
1038   }
1039
1040   /*!
1041   \brief Send a message to create a variable group on server side
1042   \param[in] id String identity of variable group that will be created on server
1043   \param [in] client client to which we will send this adding action
1044   */
1045   void CFile::sendAddVariableGroup(const string& id, CContextClient* client)
1046   {
1047      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1048   }
1049
1050   /*
1051     Send message to add a variable into a file within a certain client
1052     \param [in] id String identity of a variable
1053     \param [in] client client to which we will send this adding action
1054   */
1055   void CFile::sendAddVariable(const string& id, CContextClient* client)
1056   {
1057      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1058   }
1059
1060   /*!
1061   \brief Receive a message annoucing the creation of a variable on server side
1062   \param[in] event Received event
1063   */
1064   void CFile::recvAddVariable(CEventServer& event)
1065   {
1066
1067      CBufferIn* buffer = event.subEvents.begin()->buffer;
1068      string id;
1069      *buffer>>id;
1070      get(id)->recvAddVariable(*buffer);
1071   }
1072
1073   /*!
1074   \brief Receive a message annoucing the creation of a variable on server side
1075   \param[in] buffer Buffer containing message
1076   */
1077   void CFile::recvAddVariable(CBufferIn& buffer)
1078   {
1079      string id;
1080      buffer>>id;
1081      addVariable(id);
1082   }
1083
1084   /*!
1085   \brief Receive a message annoucing the creation of a variable group on server side
1086   \param[in] event Received event
1087   */
1088   void CFile::recvAddVariableGroup(CEventServer& event)
1089   {
1090
1091      CBufferIn* buffer = event.subEvents.begin()->buffer;
1092      string id;
1093      *buffer>>id;
1094      get(id)->recvAddVariableGroup(*buffer);
1095   }
1096
1097   /*!
1098   \brief Receive a message annoucing the creation of a variable group on server side
1099   \param[in] buffer Buffer containing message
1100   */
1101   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1102   {
1103      string id;
1104      buffer>>id;
1105      addVariableGroup(id);
1106   }
1107
1108   /*!
1109     \brief Sending all active (enabled) fields from client to server.
1110   Each field is identified uniquely by its string identity. Not only should we
1111   send the id to server but also we need to send ids of reference domain and reference axis.
1112   With these two id, it's easier to make reference to grid where all data should be written.
1113   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1114   */
1115   void CFile::sendEnabledFields(CContextClient* client)
1116   {
1117     size_t size = this->enabledFields.size();
1118     for (size_t i = 0; i < size; ++i)
1119     {
1120       CField* field = this->enabledFields[i];
1121       this->sendAddField(field->getId(), client);
1122       field->sendAllAttributesToServer(client);
1123       field->sendAddAllVariables(client);
1124     }
1125   }
1126
1127
1128   /*!
1129   \brief Dispatch event received from client
1130      Whenever a message is received in buffer of server, it will be processed depending on
1131   its event type. A new event type should be added in the switch list to make sure
1132   it processed on server side.
1133   \param [in] event: Received message
1134   */
1135   bool CFile::dispatchEvent(CEventServer& event)
1136   {
1137      if (SuperClass::dispatchEvent(event)) return true;
1138      else
1139      {
1140        switch(event.type)
1141        {
1142           case EVENT_ID_ADD_FIELD :
1143             recvAddField(event);
1144             return true;
1145             break;
1146
1147           case EVENT_ID_ADD_FIELD_GROUP :
1148             recvAddFieldGroup(event);
1149             return true;
1150             break;
1151
1152            case EVENT_ID_ADD_VARIABLE :
1153             recvAddVariable(event);
1154             return true;
1155             break;
1156
1157           case EVENT_ID_ADD_VARIABLE_GROUP :
1158             recvAddVariableGroup(event);
1159             return true;
1160             break;
1161           default :
1162              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1163           return false;
1164        }
1165      }
1166   }
1167
1168
1169
1170
1171   ///---------------------------------------------------------------
1172
1173} // namespace xios
Note: See TracBrowser for help on using the repository browser.