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

Last change on this file since 1486 was 1486, checked in by oabramkina, 5 years ago

XIOS_DEV_CMIP: minor modifications for reading UGRID.

Using attribute nvertex defined by a user and not deduced from metadata of a file being read.
Taking into account the fact that the bounds attribute is not required by UGRID.

  • 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: 39.9 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("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 == 1)
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("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      bool readMetaDataPar = true;
660      if (!context->hasServer) readMetaDataPar = (read_metadata_par.isEmpty()) ? false : read_metadata_par;
661
662      if (isOpen) data_out->closeFile();
663      bool ugridConvention = !convention.isEmpty() ? (convention == convention_attr::UGRID) : false;
664      if (time_counter_name.isEmpty())
665        data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective, readMetaDataPar, ugridConvention));
666      else
667        data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective, readMetaDataPar, ugridConvention, time_counter_name));
668      isOpen = true;
669    }
670  }
671
672   //! Close file
673   void CFile::close(void)
674   {
675     if (!allZoneEmpty)
676       if (isOpen)
677       {
678         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
679          this->data_out->closeFile();
680         else
681          this->data_in->closeFile();
682        isOpen = false;
683       }
684      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
685   }
686   //----------------------------------------------------------------
687
688   void CFile::readAttributesOfEnabledFieldsInReadMode()
689   {
690     if (enabledFields.empty()) return;
691
692     // Just check file and try to open it
693     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
694
695     checkReadFile();
696
697     for (int idx = 0; idx < enabledFields.size(); ++idx)
698     {
699        // First of all, find out which domain and axis associated with this field
700        enabledFields[idx]->solveGridReference();
701
702        // Read attributes of domain and axis from this file
703        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
704
705        // Now complete domain and axis associated with this field
706        enabledFields[idx]->solveGenerateGrid();
707
708        // Read necessary value from file
709        this->data_in->readFieldAttributesValues(enabledFields[idx]);
710
711        // Fill attributes for base reference
712        enabledFields[idx]->solveGridDomainAxisBaseRef();
713     }
714
715     // Now everything is ok, close it
716     close();
717   }
718
719
720   /*!
721   \brief Parse xml file and write information into file object
722   \param [in] node xmld node corresponding in xml file
723   */
724   void CFile::parse(xml::CXMLNode & node)
725   {
726      SuperClass::parse(node);
727
728      if (node.goToChildElement())
729      {
730        do
731        {
732           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
733           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
734        } while (node.goToNextElement());
735        node.goToParentElement();
736      }
737
738   }
739   //----------------------------------------------------------------
740
741   /*!
742   \brief Represent a file in form of string with all its info
743   \return String
744   */
745   StdString CFile::toString(void) const
746   {
747      StdOStringStream oss;
748
749      oss << "<" << CFile::GetName() << " ";
750      if (this->hasId())
751         oss << " id=\"" << this->getId() << "\" ";
752      oss << SuperClassAttribute::toString() << ">" << std::endl;
753      if (this->getVirtualFieldGroup() != NULL)
754         oss << *this->getVirtualFieldGroup() << std::endl;
755      oss << "</" << CFile::GetName() << " >";
756      return (oss.str());
757   }
758
759   //----------------------------------------------------------------
760
761   /*!
762   \brief Find all inheritace among objects in a file.
763   \param [in] apply (true) write attributes of parent into ones of child if they are empty
764                     (false) write attributes of parent into a new container of child
765   \param [in] parent
766   */
767   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
768   {
769      SuperClassAttribute::setAttributes(parent,apply);
770      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
771      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
772   }
773
774   //----------------------------------------------------------------
775
776   /*!
777   \brief Resolve all reference of active fields.
778      In order to know exactly which data each active field has, a search for all its
779   reference to find its parents or/and its base reference object must be done. Moreover
780   during this search, there are some information that can only be sent to server AFTER
781   all information of active fields are created on server side, e.g: checking mask or index
782   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
783   */
784   void CFile::solveOnlyRefOfEnabledFields(bool sendToServer)
785   {
786     int size = this->enabledFields.size();
787     for (int i = 0; i < size; ++i)
788     {
789       this->enabledFields[i]->solveOnlyReferenceEnabledField(sendToServer);
790     }
791   }
792
793   void CFile::checkGridOfEnabledFields()
794   { 
795     int size = this->enabledFields.size();
796     for (int i = 0; i < size; ++i)
797     {
798       this->enabledFields[i]->checkGridOfEnabledFields();
799     }
800   }
801
802   void CFile::sendGridComponentOfEnabledFields()
803   { 
804     int size = this->enabledFields.size();
805     for (int i = 0; i < size; ++i)
806     {
807       this->enabledFields[i]->sendGridComponentOfEnabledFields();
808     }
809   }
810
811   void CFile::sendGridOfEnabledFields()
812   { 
813     int size = this->enabledFields.size();
814     for (int i = 0; i < size; ++i)
815     {
816       this->enabledFields[i]->sendGridOfEnabledFields();
817     }
818   }
819
820   void CFile::generateNewTransformationGridDest()
821   {
822     int size = this->enabledFields.size();
823     for (int i = 0; i < size; ++i)
824     {
825       this->enabledFields[i]->generateNewTransformationGridDest();
826     }
827   }
828
829   /*!
830   \brief Resolve all reference of active fields.
831      In order to know exactly which data each active field has, a search for all its
832   reference to find its parents or/and its base reference object must be done. Moreover
833   during this search, there are some information that can only be sent to server AFTER
834   all information of active fields are created on server side, e.g: checking mask or index
835   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
836   */
837   void CFile::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
838   {
839     int size = this->enabledFields.size();
840     for (int i = 0; i < size; ++i)
841     {       
842      this->enabledFields[i]->solveAllEnabledFieldsAndTransform();
843     }
844   }
845
846   /*!
847    * Constructs the filter graph for each active field.
848    *
849    * \param gc the garbage collector to use when building the filter graph
850    */
851   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
852   {
853     int size = this->enabledFields.size();
854     for (int i = 0; i < size; ++i)
855     {
856       this->enabledFields[i]->buildFilterGraph(gc, true);
857     }
858   }
859
860   /*!
861    * Post-process the filter graph for each active field.
862    */
863   void CFile::postProcessFilterGraph()
864   {
865     int size = this->enabledFields.size();
866     for (int i = 0; i < size; ++i)
867     {
868       this->enabledFields[i]->checkIfMustAutoTrigger();
869     }
870   }
871
872   /*!
873     Prefetching the data for enabled fields read from file.
874   */
875   void CFile::prefetchEnabledReadModeFields(void)
876   {
877     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
878       return;
879
880     int size = this->enabledFields.size();
881     for (int i = 0; i < size; ++i)
882       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
883   }
884
885   /*!
886     Do all pre timestep operations for enabled fields in read mode:
887      - Check that the data excepted from server has been received
888      - Check if some filters must auto-trigger
889   */
890   void CFile::doPreTimestepOperationsForEnabledReadModeFields(void)
891   {
892     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
893       return;
894
895     int size = this->enabledFields.size();
896     for (int i = 0; i < size; ++i)
897     {
898       this->enabledFields[i]->checkForLateDataFromServer();
899       this->enabledFields[i]->autoTriggerIfNeeded();
900     }
901   }
902
903   /*!
904     Do all post timestep operations for enabled fields in read mode:
905      - Prefetch the data read from file when needed
906   */
907   void CFile::doPostTimestepOperationsForEnabledReadModeFields(void)
908   {
909     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
910       return;
911
912     int size = this->enabledFields.size();
913     for (int i = 0; i < size; ++i)
914     {
915       this->enabledFields[i]->sendReadDataRequestIfNeeded();
916     }
917   }
918
919   void CFile::solveFieldRefInheritance(bool apply)
920   {
921      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
922      std::vector<CField*> allF = this->getAllFields();
923      for (unsigned int i = 0; i < allF.size(); i++)
924         allF[i]->solveRefInheritance(apply);
925   }
926
927   //----------------------------------------------------------------
928
929   /*!
930   \brief Add a field into file.
931      A field is added into file and it will be written out if the file is enabled and
932   level of this field is smaller than level_output. A new field won't be created if one
933   with id has already existed
934   \param [in] id String identity of new field
935   \return Pointer to added (or already existed) field
936   */
937   CField* CFile::addField(const string& id)
938   {
939     return vFieldGroup->createChild(id);
940   }
941
942   /*!
943   \brief Add a field group into file.
944      A field group is added into file and it will play a role as parents for fields.
945   A new field group won't be created if one with id has already existed
946   \param [in] id String identity of new field group
947   \return Pointer to added (or already existed) field group
948   */
949   CFieldGroup* CFile::addFieldGroup(const string& id)
950   {
951     return vFieldGroup->createChildGroup(id);
952   }
953
954   /*!
955   \brief Add a variable into file.
956      A variable is added into file and if one with id has already existed, pointer to
957   it will be returned.
958      Variable as long as attributes are information container of file.
959   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
960   to fill in (extra) information for a file.
961   \param [in] id String identity of new variable
962   \return Pointer to added (or already existed) variable
963   */
964   CVariable* CFile::addVariable(const string& id)
965   {
966     return vVariableGroup->createChild(id);
967   }
968
969   /*!
970   \brief Add a variable group into file.
971      A variable group is added into file and it will play a role as parents for variables.
972   A new variable group won't be created if one with id has already existed
973   \param [in] id String identity of new variable group
974   \return Pointer to added (or already existed) variable group
975   */
976   CVariableGroup* CFile::addVariableGroup(const string& id)
977   {
978     return vVariableGroup->createChildGroup(id);
979   }
980
981   void CFile::setContextClient(CContextClient* newContextClient)
982   {
983     client = newContextClient;
984     size_t size = this->enabledFields.size();
985     for (size_t i = 0; i < size; ++i)
986     {
987       this->enabledFields[i]->setContextClient(newContextClient);
988     }
989   }
990
991   CContextClient* CFile::getContextClient()
992   {
993     return client;
994   }
995
996   void CFile::setReadContextClient(CContextClient* readContextclient)
997   {
998     read_client = readContextclient;
999   }
1000
1001   CContextClient* CFile::getReadContextClient()
1002   {
1003     return read_client;
1004   }
1005
1006   /*!
1007   \brief Send a message to create a field on server side
1008   \param[in] id String identity of field that will be created on server
1009   */
1010   void CFile::sendAddField(const string& id, CContextClient* client)
1011   {
1012      sendAddItem(id, EVENT_ID_ADD_FIELD, client);
1013   }
1014
1015   /*!
1016   \brief Send a message to create a field group on server side
1017   \param[in] id String identity of field group that will be created on server
1018   */
1019   void CFile::sendAddFieldGroup(const string& id, CContextClient* client)
1020   {
1021      sendAddItem(id, (int)EVENT_ID_ADD_FIELD_GROUP, client);
1022   }
1023
1024   /*!
1025   \brief Receive a message annoucing the creation of a field on server side
1026   \param[in] event Received event
1027   */
1028   void CFile::recvAddField(CEventServer& event)
1029   {
1030
1031      CBufferIn* buffer = event.subEvents.begin()->buffer;
1032      string id;
1033      *buffer>>id;
1034      get(id)->recvAddField(*buffer);
1035   }
1036
1037   /*!
1038   \brief Receive a message annoucing the creation of a field on server side
1039   \param[in] buffer Buffer containing message
1040   */
1041   void CFile::recvAddField(CBufferIn& buffer)
1042   {
1043      string id;
1044      buffer>>id;
1045      addField(id);
1046   }
1047
1048   /*!
1049   \brief Receive a message annoucing the creation of a field group on server side
1050   \param[in] event Received event
1051   */
1052   void CFile::recvAddFieldGroup(CEventServer& event)
1053   {
1054
1055      CBufferIn* buffer = event.subEvents.begin()->buffer;
1056      string id;
1057      *buffer>>id;
1058      get(id)->recvAddFieldGroup(*buffer);
1059   }
1060
1061   /*!
1062   \brief Receive a message annoucing the creation of a field group on server side
1063   \param[in] buffer Buffer containing message
1064   */
1065   void CFile::recvAddFieldGroup(CBufferIn& buffer)
1066   {
1067      string id;
1068      buffer>>id;
1069      addFieldGroup(id);
1070   }
1071
1072   /*!
1073   \brief Send messages to duplicate all variables on server side
1074      Because each variable has also its attributes. So first thing to do is replicate
1075   all these attributes on server side. Because variable can have a value, the second thing
1076   is to duplicate this value on server, too.
1077   */
1078   void CFile::sendAddAllVariables(CContextClient* client)
1079   {
1080     std::vector<CVariable*> allVar = getAllVariables();
1081     std::vector<CVariable*>::const_iterator it = allVar.begin();
1082     std::vector<CVariable*>::const_iterator itE = allVar.end();
1083
1084     for (; it != itE; ++it)
1085     {
1086       this->sendAddVariable((*it)->getId(), client);
1087       (*it)->sendAllAttributesToServer(client);
1088       (*it)->sendValue(client);
1089     }
1090   }
1091
1092   /*!
1093   \brief Send a message to create a variable group on server side
1094   \param[in] id String identity of variable group that will be created on server
1095   \param [in] client client to which we will send this adding action
1096   */
1097   void CFile::sendAddVariableGroup(const string& id, CContextClient* client)
1098   {
1099      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1100   }
1101
1102   /*
1103     Send message to add a variable into a file within a certain client
1104     \param [in] id String identity of a variable
1105     \param [in] client client to which we will send this adding action
1106   */
1107   void CFile::sendAddVariable(const string& id, CContextClient* client)
1108   {
1109      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1110   }
1111
1112   /*!
1113   \brief Receive a message annoucing the creation of a variable on server side
1114   \param[in] event Received event
1115   */
1116   void CFile::recvAddVariable(CEventServer& event)
1117   {
1118
1119      CBufferIn* buffer = event.subEvents.begin()->buffer;
1120      string id;
1121      *buffer>>id;
1122      get(id)->recvAddVariable(*buffer);
1123   }
1124
1125   /*!
1126   \brief Receive a message annoucing the creation of a variable on server side
1127   \param[in] buffer Buffer containing message
1128   */
1129   void CFile::recvAddVariable(CBufferIn& buffer)
1130   {
1131      string id;
1132      buffer>>id;
1133      addVariable(id);
1134   }
1135
1136   /*!
1137   \brief Receive a message annoucing the creation of a variable group on server side
1138   \param[in] event Received event
1139   */
1140   void CFile::recvAddVariableGroup(CEventServer& event)
1141   {
1142
1143      CBufferIn* buffer = event.subEvents.begin()->buffer;
1144      string id;
1145      *buffer>>id;
1146      get(id)->recvAddVariableGroup(*buffer);
1147   }
1148
1149   /*!
1150   \brief Receive a message annoucing the creation of a variable group on server side
1151   \param[in] buffer Buffer containing message
1152   */
1153   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1154   {
1155      string id;
1156      buffer>>id;
1157      addVariableGroup(id);
1158   }
1159
1160   /*!
1161     \brief Sending all active (enabled) fields from client to server.
1162   Each field is identified uniquely by its string identity. Not only should we
1163   send the id to server but also we need to send ids of reference domain and reference axis.
1164   With these two id, it's easier to make reference to grid where all data should be written.
1165   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1166   */
1167   void CFile::sendEnabledFields(CContextClient* client)
1168   {
1169     size_t size = this->enabledFields.size();
1170     for (size_t i = 0; i < size; ++i)
1171     {
1172       CField* field = this->enabledFields[i];
1173       this->sendAddField(field->getId(), client);
1174       field->checkTimeAttributes();
1175       field->sendAllAttributesToServer(client);
1176       field->sendAddAllVariables(client);
1177     }
1178   }
1179
1180
1181   /*!
1182   \brief Dispatch event received from client
1183      Whenever a message is received in buffer of server, it will be processed depending on
1184   its event type. A new event type should be added in the switch list to make sure
1185   it processed on server side.
1186   \param [in] event: Received message
1187   */
1188   bool CFile::dispatchEvent(CEventServer& event)
1189   {
1190      if (SuperClass::dispatchEvent(event)) return true;
1191      else
1192      {
1193        switch(event.type)
1194        {
1195           case EVENT_ID_ADD_FIELD :
1196             recvAddField(event);
1197             return true;
1198             break;
1199
1200           case EVENT_ID_ADD_FIELD_GROUP :
1201             recvAddFieldGroup(event);
1202             return true;
1203             break;
1204
1205            case EVENT_ID_ADD_VARIABLE :
1206             recvAddVariable(event);
1207             return true;
1208             break;
1209
1210           case EVENT_ID_ADD_VARIABLE_GROUP :
1211             recvAddVariableGroup(event);
1212             return true;
1213             break;
1214           default :
1215              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1216           return false;
1217        }
1218      }
1219   }
1220
1221
1222
1223
1224   ///---------------------------------------------------------------
1225
1226} // namespace xios
Note: See TracBrowser for help on using the repository browser.