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

Last change on this file since 1232 was 1232, checked in by mhnguyen, 7 years ago

Fixing the blocking problem where there are more servers than the number of grid band distribution

+) Correct this problem not only for writing but also for reading
+) Allow "zero-size" domain, axis (i.e: domain, axis with ni = 0, and/or nj=0)

Test
+) On Curie
+) Work in both cases: Read and Write data

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