source: XIOS3/trunk/src/node/file.cpp @ 2589

Last change on this file since 2589 was 2589, checked in by jderouillat, 8 months ago

Specify the usage of the xios namespace to overload the MPI funtions

  • 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: 45.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#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),  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), 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   TRY
56   {
57     return (name.isEmpty() ? getId() : name) + (name_suffix.isEmpty() ? StdString("") :  name_suffix.getValue());
58   }
59   CATCH
60
61   //----------------------------------------------------------------
62   /*!
63   \brief Get data writer object.
64   Each enabled file in xml represents a physical netcdf file.
65   This function allows to access the data writer object.
66   \return data writer object.
67   */
68   std::shared_ptr<CDataOutput> CFile::getDataOutput(void) const
69   TRY
70   {
71      return data_out;
72   }
73   CATCH
74
75   /*!
76   \brief Get data reader object.
77   Each enabled file in xml represents a physical netcdf file.
78   This function allows to access the data reader object.
79   \return data reader object.
80   */
81   std::shared_ptr<CDataInput> CFile::getDataInput(void) const
82   TRY
83   {
84      return data_in;
85   }
86   CATCH
87
88   /*!
89   \brief Get virtual field group
90      In each file, there always exists a field group which is the ancestor of all
91   fields in the file. This is considered be virtual because it is created automatically during
92   file initialization and it normally doesn't appear on xml file
93   \return Pointer to field group
94   */
95   CFieldGroup* CFile::getVirtualFieldGroup(void) const
96   TRY
97   {
98      return (this->vFieldGroup);
99   }
100   CATCH
101
102   /*!
103   \brief Get virtual variable group
104      In each file, there always exists a variable group which is the ancestor of all
105   variable in the file. This is considered be virtual because it is created automatically during
106   file initialization and it normally doesn't appear on xml file
107   \return Pointer to variable group
108   */
109   CVariableGroup* CFile::getVirtualVariableGroup(void) const
110   TRY
111   {
112      return (this->vVariableGroup);
113   }
114   CATCH
115
116   //! Get all fields of a file
117   std::vector<CField*> CFile::getAllFields(void) const
118   TRY
119   {
120      return (this->vFieldGroup->getAllChildren());
121   }
122   CATCH
123
124   //! Get all variables of a file
125   std::vector<CVariable*> CFile::getAllVariables(void) const
126   TRY
127   {
128      return (this->vVariableGroup->getAllChildren());
129   }
130   CATCH
131
132   //----------------------------------------------------------------
133   /*!
134   \brief Get all enabled fields of file
135      A field is considered to be enabled if it fullfil these conditions: it is enabled, inside a enabled file
136   and its own level is not larger than file output level.
137   \param [in] default_outputlevel default value output level of file
138   \param [in] default_level default value level of field
139   \param [in] default_enabled flag determine by default if field is enabled
140   \return Vector of pointers of enabled fields
141   */
142   std::vector<CField*> CFile::getEnabledFields(int default_outputlevel,
143                                                int default_level,
144                                                bool default_enabled)
145   TRY
146   {
147      if (!this->enabledFields.empty()) return (this->enabledFields);
148
149      const int _outputlevel = (!output_level.isEmpty()) ? output_level.getValue() : default_outputlevel;
150      std::vector<CField*>::iterator it;
151      this->enabledFields = this->getAllFields();
152
153      std::vector<CField*> newEnabledFields;
154
155      for ( it = this->enabledFields.begin(); it != this->enabledFields.end(); it++ )
156      {
157         if (!(*it)->enabled.isEmpty()) // Si l'attribut 'enabled' est dfini ...
158         {
159            if (! (*it)->enabled.getValue()) continue;
160         }
161         else // Si l'attribut 'enabled' n'est pas dfini ...
162         {
163            if (!default_enabled) continue;
164         }
165
166         if (!(*it)->level.isEmpty()) // Si l'attribut 'level' est dfini ...
167         {
168            if ((*it)->level.getValue() > _outputlevel) continue;
169         }
170         else // Si l'attribut 'level' n'est pas dfini ...
171         {
172            if (default_level > _outputlevel) continue;
173         }
174
175         newEnabledFields.push_back(*it);
176      }
177      enabledFields = newEnabledFields;
178
179      return (this->enabledFields);
180   }
181   CATCH_DUMP_ATTR
182
183   void CFile::replaceEnabledFields(CField* fieldIn, CField* fieldOut)
184   TRY
185   {
186     for(auto& enableField : enabledFields) if (enableField==fieldIn) enableField=fieldOut ;
187   }
188   CATCH_DUMP_ATTR
189
190   //----------------------------------------------------------------
191   //! Change virtual field group to a new one
192   void CFile::setVirtualFieldGroup(CFieldGroup* newVFieldGroup)
193   TRY
194   {
195      this->vFieldGroup = newVFieldGroup;
196   }
197   CATCH_DUMP_ATTR
198
199   //! Change virtual variable group to new one
200   void CFile::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
201   TRY
202   {
203      this->vVariableGroup = newVVariableGroup;
204   }
205   CATCH_DUMP_ATTR
206
207   //----------------------------------------------------------------
208   bool CFile::isSyncTime(void)
209   TRY
210   {
211     CContext* context = CContext::getCurrent();
212     const CDate& currentDate = context->calendar->getCurrentDate();
213     if (!sync_freq.isEmpty())
214     {
215       if (lastSync + sync_freq.getValue() < currentDate)
216       {
217         lastSync = currentDate;
218         return true;
219        }
220      }
221      return false;
222    }
223    CATCH_DUMP_ATTR
224
225   //! Initialize a file in order to write into it
226   void CFile::initWrite(void)
227   TRY
228   {
229      CContext* context = CContext::getCurrent();
230      const CDate& currentDate = context->calendar->getCurrentDate();
231
232      lastSync  = currentDate;
233      lastSplit = currentDate;
234      if (!split_freq.isEmpty())
235      {
236        StdString keySuffix("CFile::"+getFileOutputName()+"::") ; 
237        if (context->registryIn->foundKey(keySuffix+"splitStart") && context->registryIn->foundKey(keySuffix+"splitEnd"))
238        {
239          CDate savedSplitStart(*context->getCalendar()), savedSplitEnd(*context->getCalendar());
240          context->registryIn->getKey(keySuffix+"splitStart", savedSplitStart);
241          context->registryIn->getKey(keySuffix+"splitEnd",   savedSplitEnd);
242
243          if (savedSplitStart <= lastSplit && lastSplit <= savedSplitEnd)
244            lastSplit = savedSplitStart;
245        }
246      }
247      isOpen = false;     
248
249      set<StdString> setAxis;
250      set<StdString> setDomains;
251
252      std::vector<CField*>::iterator it, end = this->enabledFields.end();
253      for (it = this->enabledFields.begin(); it != end; it++)
254      {
255         CField* field = *it;         
256         std::vector<CAxis*> vecAxis = field->getGrid()->getAxis();
257         for (size_t i = 0; i < vecAxis.size(); ++i)
258           setAxis.insert(vecAxis[i]->getAxisOutputName());
259         std::vector<CDomain*> vecDomains = field->getGrid()->getDomains();
260         for (size_t i = 0; i < vecDomains.size(); ++i)
261           setDomains.insert(vecDomains[i]->getDomainOutputName());
262      }
263      nbAxis = setAxis.size();
264      nbDomains = setDomains.size();
265
266      // create sub communicator for file
267      if (type == CFile::type_attr::multiple_file)
268      {
269        createSubComFile();
270      }
271      else
272      {
273        // NetCDF runs now write of null data
274        xios::MPI_Comm_dup(context->intraComm_, &fileComm) ;
275      }
276
277      if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
278    }
279    CATCH_DUMP_ATTR
280
281    //! Initialize a file in order to write into it
282    void CFile::initRead(void)
283    TRY
284    {
285      CContext* context = CContext::getCurrent();
286      if (checkRead) return;
287      //createSubComFile();
288      allZoneEmpty = false; 
289      xios::MPI_Comm_dup(context->intraComm_, &fileComm) ;
290      checkRead = true;
291    }
292    CATCH_DUMP_ATTR
293
294    /*!
295      Create a sub communicator in which processes participate in reading/opening file
296      Seems to be deprecated (allZoneEmpty too, which is always false)
297    */
298    void CFile::createSubComFile()
299    TRY
300    {
301      CContext* context = CContext::getCurrent();
302
303      // create sub communicator for file
304      allZoneEmpty = true;     
305      std::vector<CField*>::iterator it, end = this->enabledFields.end();
306      for (it = this->enabledFields.begin(); it != end; it++)
307      {
308         CField* field = *it;
309         bool nullGrid = (nullptr == field->getGrid());
310         allZoneEmpty &= nullGrid ? false : !field->getGrid()->doGridHaveDataToWrite();
311      }
312
313      int color = allZoneEmpty ? 0 : 1;
314      xios::MPI_Comm_split(context->intraComm_, color, context->intraCommRank_, &fileComm);
315      if (allZoneEmpty) xios::MPI_Comm_free(&fileComm);
316    }
317    CATCH_DUMP_ATTR
318
319    /*
320       Check condition to write into a file
321       For now, we only use the level-2 server to write files (if this mode is activated)
322       or classical server to do this job.
323    */
324    void CFile::checkWriteFile(void)
325    TRY
326    {
327      CContext* context = CContext::getCurrent();
328
329      if (mode.isEmpty() || mode.getValue() == mode_attr::write)
330      {
331        CTimer::get("Files : create headers").resume();
332        if (!isOpen) createHeader();
333        CTimer::get("Files : create headers").suspend();
334        checkSync();
335      }       
336      checkSplit(); 
337    }
338    CATCH_DUMP_ATTR
339
340    /*
341       Check condition to read from a file
342       For now, we only use the level-1 server to write files (if this mode is activated)
343       or classical server to do this job.
344       This function can be used by client for reading metadata
345    */
346    void CFile::checkReadFile(void)
347    TRY
348    {
349      CContext* context = CContext::getCurrent();
350      // Done by classical server or secondary server
351      // TODO: This condition should be changed soon. It only works with maximum number of level as 2
352
353//ym      if (CServer::serverLevel == 0 || CServer::serverLevel == 1)
354// ym client must doing it also
355//      if (context->getServiceType()==CServicesManager::IO_SERVER || context->getServiceType()==CServicesManager::GATHERER)
356//      {
357        if (!mode.isEmpty() && mode.getValue() == mode_attr::read)
358        {
359          CTimer::get("Files : open headers").resume();
360         
361          if (!isOpen) openInReadMode();
362
363          CTimer::get("Files : open headers").suspend();
364        }
365        //checkSplit(); // Really need for reading?
366 //     }
367    }
368    CATCH_DUMP_ATTR
369
370    /*!
371      Verify if a process participates in an opening-file communicator
372      \return true if the process doesn't participate in opening file
373    */
374    bool CFile::isEmptyZone()
375    TRY
376    {
377      return allZoneEmpty;
378    }
379    CATCH_DUMP_ATTR
380
381    /*!
382    \brief Verify if synchronisation should be done
383        If syn option is enabled, syn frequence and current time will be used to
384    calculate the moment to syn file(s)
385    \return True if it is the moment to synchronize file, otherwise false
386    */
387   bool CFile::checkSync(void)
388   TRY
389   {
390     CContext* context = CContext::getCurrent();
391     const CDate& currentDate = context->calendar->getCurrentDate();
392     if (!sync_freq.isEmpty())
393     {
394       if (lastSync + sync_freq.getValue() <= currentDate)
395       {
396         lastSync = currentDate;
397         data_out->syncFile();
398         return true;
399        }
400      }
401      return false;
402    }
403   CATCH_DUMP_ATTR
404
405    /*!
406    \brief Verify if splitting should be done
407        If split option is enabled, split frequence and current time will be used to
408    calculate the moment to split file
409    \return True if it is the moment to split file, otherwise false
410    */
411    bool CFile::checkSplit(void)
412    TRY
413    {
414      CContext* context = CContext::getCurrent();
415      const CDate& currentDate = context->calendar->getCurrentDate();
416      if (!split_freq.isEmpty())
417      {
418        if (currentDate > lastSplit + split_freq.getValue())
419        {
420          lastSplit = lastSplit + split_freq.getValue();
421          std::vector<CField*>::iterator it, end = this->enabledFields.end();
422/*          for (it = this->enabledFields.begin(); it != end; it++)
423          {
424            (*it)->resetNStep();
425            (*it)->resetNStepMax();
426          }*/
427          if (mode.isEmpty() || mode.getValue() == mode_attr::write)
428            createHeader();
429          else
430            openInReadMode();
431          return true;
432        }
433      }
434      return false;
435    }
436    CATCH_DUMP_ATTR
437
438
439   /*!
440   \brief Create header of netcdf file
441   There are some information to fill in header of each netcdf.
442   */
443   void CFile::createHeader(void)
444   TRY
445   {
446      CContext* context = CContext::getCurrent();
447     
448      if (!allZoneEmpty)
449      {
450         StdString filename = getFileOutputName();
451
452// determine splitting format in the file name  : firstPart%start_date%middlePart%end_date%lastPart
453
454         std::string strStartDate="%start_date%" ;
455         std::string strEndDate="%end_date%" ;
456
457         std::string firstPart ;
458         std::string middlePart ;
459         std::string lastPart ;
460         size_t pos1, pos2 ;
461         bool hasStartDate=false ;
462         bool hasEndDate=false ;
463         bool hasSplit = (!split_freq.isEmpty());
464                 
465         pos1=filename.find(strStartDate) ;
466         if (pos1!=std::string::npos)
467         {
468           firstPart=filename.substr(0,pos1) ;
469           pos1+=strStartDate.size() ;
470           hasStartDate=true ;
471         }
472         else pos1=0 ;
473
474         pos2=filename.find(strEndDate,pos1) ;
475         if (pos2!=std::string::npos)
476         {
477           middlePart=filename.substr(pos1,pos2-pos1) ;
478           pos2+=strEndDate.size() ;
479           lastPart=filename.substr(pos2,filename.size()-pos2) ;
480           hasEndDate=true ;
481         }
482         else middlePart=filename.substr(pos1,filename.size()) ;
483
484         if (!hasStartDate && !hasEndDate)
485         {
486           hasStartDate=true ;
487           hasEndDate=true;
488           firstPart=middlePart ;
489           if (hasSplit) firstPart +="_";
490           middlePart="-" ;
491         }
492   
493         StdOStringStream oss;
494
495         if (!split_freq.isEmpty())
496         {
497           CDate split_start ;
498           CDate splitEnd ;
499           if (!split_start_offset.isEmpty()) split_start=lastSplit + split_start_offset ;
500           else split_start=lastSplit ;
501
502           splitEnd = lastSplit + split_freq ;
503           if (!split_last_date.isEmpty())
504           {
505             CDate splitLastDate=CDate::FromString(split_last_date,*CContext::getCurrent()->getCalendar()) ;
506             if( splitLastDate < splitEnd)  splitEnd=splitLastDate ;
507           }
508           
509           if (!split_end_offset.isEmpty()) splitEnd = splitEnd + split_end_offset;
510           else splitEnd = splitEnd - 1 * Second;
511
512           string splitFormat;
513           if (split_freq_format.isEmpty())
514           {
515             CDuration splitFreq = split_freq.getValue();
516             splitFreq.solveTimeStep(*CContext::getCurrent()->getCalendar());
517             if (splitFreq.second != 0) splitFormat = "%y%mo%d%h%mi%s";
518             else if (splitFreq.minute != 0) splitFormat = "%y%mo%d%h%mi";
519             else if (splitFreq.hour != 0) splitFormat = "%y%mo%d%h";
520             else if (splitFreq.day != 0) splitFormat = "%y%mo%d";
521             else if (splitFreq.month != 0) splitFormat = "%y%mo";
522             else splitFormat = "%y";
523           }
524           else splitFormat = split_freq_format;
525
526           oss << firstPart ;
527           if (hasStartDate) oss << split_start.getStr(splitFormat) ;
528           oss << middlePart ;
529           if (hasEndDate) oss << splitEnd.getStr(splitFormat);
530           oss << lastPart ;
531
532           StdString keySuffix("CFile::"+getFileOutputName()+"::") ; 
533           context->registryOut->setKey(keySuffix+"splitStart", lastSplit);
534           context->registryOut->setKey(keySuffix+"splitEnd",   splitEnd);
535         }
536         else oss<<firstPart<<lastPart ;
537
538        bool append = !this->append.isEmpty() && this->append.getValue();
539
540         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
541         bool useCFConvention = convention.isEmpty() || convention == convention_attr::CF;
542
543         bool multifile = true;
544         if (!type.isEmpty())
545         {
546           if (type == type_attr::one_file) multifile = false;
547           else if (type == type_attr::multiple_file) multifile = true;
548
549         }
550#ifndef USING_NETCDF_PAR
551         if (!multifile)
552         {
553            info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
554            multifile = true;
555          }
556#endif
557         if (multifile)
558         {
559            int commSize, commRank;
560            MPI_Comm_size(fileComm, &commSize);
561            MPI_Comm_rank(fileComm, &commRank);
562
563            if (context->intraCommSize_ > 1)
564            {
565              oss << "_" ;
566              int width=0; int n = commSize-1;
567              while (n != 0) { n = n / 10; width++;}
568              if (!min_digits.isEmpty())
569                if (width < min_digits) width = min_digits;
570              oss.width(width);
571              oss.fill('0');
572              oss << right << commRank;
573            }
574         }
575         oss << ".nc";
576
577         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
578
579         if (isOpen) data_out->closeFile();
580
581        data_out = std::shared_ptr<CDataOutput>(new CNc4DataOutput(this, oss.str(), append, useClassicFormat, useCFConvention,
582                                                              fileComm, multifile, isCollective, time_counter_name));
583        isOpen = true;
584
585        data_out->writeFile(CFile::get(this));
586
587        if (!useCFConvention) sortEnabledFieldsForUgrid();
588
589        // Do not recreate the file structure if opening an existing file
590        if (!data_out->IsInAppendMode())
591        {
592          std::vector<CField*>::iterator it, end = this->enabledFields.end();
593          for (it = this->enabledFields.begin(); it != end; it++)
594          {
595            CField* field = *it;
596            this->data_out->writeFieldGrid(field);
597          }
598          this->data_out->writeTimeDimension();
599
600          for (it = this->enabledFields.begin(); it != end; it++)
601          {
602            CField* field = *it;
603            this->data_out->writeFieldTimeAxis(field);
604          }
605         
606          for (it = this->enabledFields.begin(); it != end; it++)
607          {
608            CField* field = *it;
609            this->data_out->writeField(field);
610          }
611
612          vector<CVariable*> listVars = getAllVariables();
613          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
614            this->data_out->writeAttribute(*it);
615
616          this->data_out->definition_end();
617        }
618        else
619        {
620          // check time axis even in append mode
621          std::vector<CField*>::iterator it, end = this->enabledFields.end();
622          for (it = this->enabledFields.begin(); it != end; it++)
623          {
624            CField* field = *it;
625            this->data_out->writeFieldTimeAxis(field);
626          }
627        }
628      }
629   }
630   CATCH_DUMP_ATTR
631
632  /*!
633  \brief Open an existing NetCDF file in read-only mode
634  */
635  void CFile::openInReadMode()
636  TRY
637  {
638    CContext* context = CContext::getCurrent();
639    MPI_Comm readComm = this->fileComm;
640
641    if (!allZoneEmpty)
642    {
643      StdString filename = getFileOutputName();
644      StdOStringStream oss;
645      oss << filename;
646
647      if (!split_freq.isEmpty())
648      {
649        string splitFormat;
650        if (split_freq_format.isEmpty())
651        {
652          CDuration splitFreq = split_freq.getValue();
653          splitFreq.solveTimeStep(*CContext::getCurrent()->getCalendar());
654          if (splitFreq.second != 0) splitFormat = "%y%mo%d%h%mi%s";
655          else if (splitFreq.minute != 0) splitFormat = "%y%mo%d%h%mi";
656          else if (splitFreq.hour != 0) splitFormat = "%y%mo%d%h";
657          else if (splitFreq.day != 0) splitFormat = "%y%mo%d";
658          else if (splitFreq.month != 0) splitFormat = "%y%mo";
659          else splitFormat = "%y";
660        }
661        else splitFormat = split_freq_format;
662        oss << "_" << lastSplit.getStr(splitFormat)
663        << "-" << (lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
664      }
665
666      bool multifile = true;
667      if (!type.isEmpty())
668      {
669        if (type == type_attr::one_file) multifile = false;
670        else if (type == type_attr::multiple_file) multifile = true;
671      }
672  #ifndef USING_NETCDF_PAR
673      if (!multifile)
674      {
675        info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
676        multifile = true;
677      }
678  #endif
679      if (multifile)
680      {
681        int commSize, commRank;
682        MPI_Comm_size(readComm, &commSize);
683        MPI_Comm_rank(readComm, &commRank);
684
685        if (context->intraCommSize_ > 1)
686        {
687          oss << "_";
688          int width = 0, n = commSize - 1;
689          while (n != 0) { n = n / 10; width++; }
690          if (!min_digits.isEmpty() && width < min_digits)
691            width = min_digits;
692          oss.width(width);
693          oss.fill('0');
694          oss << right << commRank;
695        }
696      }
697      oss << ".nc";
698
699      bool isCollective = par_access.isEmpty() || par_access == par_access_attr::collective;
700      bool readMetaDataPar = true;
701      if (context->getServiceType()==CServicesManager::CLIENT) readMetaDataPar = (read_metadata_par.isEmpty()) ? false : read_metadata_par;
702
703      if (isOpen) data_out->closeFile();
704      bool ugridConvention = !convention.isEmpty() ? (convention == convention_attr::UGRID) : false;
705      if (time_counter_name.isEmpty())
706        data_in = std::shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective, readMetaDataPar, ugridConvention));
707      else
708        data_in = std::shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective, readMetaDataPar, ugridConvention, time_counter_name));
709      isOpen = true;
710    }
711  }
712  CATCH_DUMP_ATTR
713
714   //! Close file
715   void CFile::close(void)
716   TRY
717   {
718     if (!allZoneEmpty)
719       if (isOpen)
720       {
721         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
722          this->data_out->closeFile();
723         else
724          this->data_in->closeFile();
725        isOpen = false;
726       }
727      if (fileComm != MPI_COMM_NULL) xios::MPI_Comm_free(&fileComm);
728   }
729   CATCH_DUMP_ATTR
730
731   //----------------------------------------------------------------
732
733   void CFile::readAttributesOfEnabledFieldsInReadMode()
734   TRY
735   {
736     if (enabledFields.empty()) return;
737
738     // Just check file and try to open it
739     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
740
741     checkReadFile();
742
743     for (int idx = 0; idx < enabledFields.size(); ++idx)
744     {
745        // First of all, find out which domain and axis associated with this field
746        enabledFields[idx]->solveGridReference();
747
748        // Read attributes of domain and axis from this file
749        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
750
751        // Now complete domain and axis associated with this field
752       
753       //ym => this a problem in wich order are done the grid generation. Probably metadata are read in file and after the grid is ditributed by the filter
754       // => must be checked in detail. But solveGenerated grid is not existing any more with new transformation framework
755       // enabledFields[idx]->solveGenerateGrid();
756
757        // Read necessary value from file
758        this->data_in->readFieldAttributesValues(enabledFields[idx]);
759
760        // Fill attributes for base reference
761        enabledFields[idx]->solveGridDomainAxisBaseRef();
762     }
763
764     // Now everything is ok, close it
765     close();
766   }
767   CATCH_DUMP_ATTR
768
769   void CFile::readFieldAttributesMetaData(CField* field)
770   {
771     this->data_in->readFieldAttributesMetaData(field);
772   }
773
774   void CFile::readFieldAttributesValues(CField* field)
775   {
776     this->data_in->readFieldAttributesValues(field);
777   }
778   /*!
779   \brief Parse xml file and write information into file object
780   \param [in] node xmld node corresponding in xml file
781   */
782   void CFile::parse(xml::CXMLNode & node)
783   TRY
784   {
785      SuperClass::parse(node);
786
787      if (node.goToChildElement())
788      {
789        do
790        {
791           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
792           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
793        } while (node.goToNextElement());
794        node.goToParentElement();
795      }
796   }
797   CATCH_DUMP_ATTR
798
799   //----------------------------------------------------------------
800
801   /*!
802   \brief Represent a file in form of string with all its info
803   \return String
804   */
805   StdString CFile::toString(void) const
806   TRY
807   {
808      StdOStringStream oss;
809
810      oss << "<" << CFile::GetName() << " ";
811      if (this->hasId())
812         oss << " id=\"" << this->getId() << "\" ";
813      oss << SuperClassAttribute::toString() << ">" << std::endl;
814      if (this->getVirtualFieldGroup() != NULL)
815         oss << *this->getVirtualFieldGroup() << std::endl;
816      oss << "</" << CFile::GetName() << " >";
817      return (oss.str());
818   }
819   CATCH
820
821   //----------------------------------------------------------------
822
823   /*!
824   \brief Find all inheritace among objects in a file.
825   \param [in] apply (true) write attributes of parent into ones of child if they are empty
826                     (false) write attributes of parent into a new container of child
827   \param [in] parent
828   */
829   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
830   TRY
831   {
832      SuperClassAttribute::setAttributes(parent,apply);
833      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
834      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
835   }
836   CATCH_DUMP_ATTR
837
838   //----------------------------------------------------------------
839
840   void CFile::checkGridOfEnabledFields()
841   TRY
842   { 
843     int size = this->enabledFields.size();
844     for (int i = 0; i < size; ++i)
845     {
846       this->enabledFields[i]->checkGridOfEnabledFields();
847     }
848   }
849   CATCH_DUMP_ATTR
850
851   void CFile::sendGridComponentOfEnabledFields()
852   TRY
853   { 
854     int size = this->enabledFields.size();
855     for (int i = 0; i < size; ++i)
856     {
857       this->enabledFields[i]->sendGridComponentOfEnabledFields();
858     }
859   }
860   CATCH_DUMP_ATTR
861
862   /*!
863   \brief Sorting domains with the same name (= describing the same mesh) in the decreasing order of nvertex for UGRID files.
864   This insures that the domain with the highest nvertex is written first and thus all known mesh connectivity is generated at once by this domain.
865   */
866   void CFile::sortEnabledFieldsForUgrid()
867   TRY
868   {
869     int size = this->enabledFields.size();
870     std::vector<int> domainNvertices;
871     std::vector<StdString> domainNames;
872     std::map<string, tuple<set<CDomain*>,set<CDomain*>,set<CDomain*>>> registeredDomains ;
873
874     for (int i = 0; i < size; ++i)
875     {
876       std::vector<CDomain*> domain = this->enabledFields[i]->getRelGrid()->getDomains();
877       if (domain.size() != 1)
878       {
879         ERROR("void CFile::sortEnabledFieldsForUgrid()",
880               "A domain, and only one, should be defined for grid "<< this->enabledFields[i]->getRelGrid()->getId() << ".");
881       }
882       StdString domainName = domain[0]->getDomainOutputName();
883       int nvertex;
884       if (domain[0]->nvertex.isEmpty())
885       {
886         ERROR("void CFile::sortEnabledFieldsForUgrid()",
887               "Attributes nvertex must be defined for domain "<< domain[0]->getDomainOutputName() << ".");
888       }
889       else
890         nvertex = domain[0]->nvertex;
891
892       for (int j = 0; j < i; ++j)
893       {
894         if (domainName == domainNames[j] && nvertex > domainNvertices[j])
895         {
896           CField* tmpSwap = this->enabledFields[j];
897           this->enabledFields[j] = this->enabledFields[i];
898           this->enabledFields[i] = tmpSwap;
899           domainNames.push_back(domainNames[j]);
900           domainNames[j] = domainName;
901           domainNvertices.push_back(domainNvertices[j]);
902           domainNvertices[j] = nvertex;
903         }
904         else
905         {
906           domainNames.push_back(domainName);
907           domainNvertices.push_back(nvertex);
908         }
909       }
910       if (i==0)
911       {
912         domainNames.push_back(domainName);
913         domainNvertices.push_back(nvertex);
914       }
915
916       if (nvertex==1)  std::get<0>(registeredDomains[domainName]).insert(domain[0]) ;
917       else if (nvertex==2) std::get<1>(registeredDomains[domainName]).insert(domain[0]) ;
918       else  std::get<2>(registeredDomains[domainName]).insert(domain[0]) ;
919     }
920
921     for(auto& it:registeredDomains)
922     {
923       list<CDomain*> domains ;
924       string domainName=it.first ;
925
926       for(auto& domain : std::get<0>(it.second) ) domains.push_back(domain) ;
927       for(auto& domain : std::get<1>(it.second) ) domains.push_back(domain) ;
928       for(auto& domain : std::get<2>(it.second) ) domains.push_back(domain) ;
929       
930       // for each component of a given mesh (i.e. domains with same name but different number of vertices)
931       // associate the UGRID mesh in increasing order
932       for(auto& domain : domains )
933       {
934         //domain-> computeWrittenIndex();
935         //CArray<int, 1>& indexToWrite = domain->localIndexToWriteOnServer;
936         CArray<int, 1> indexToWrite = domain->getLocalView(CElementView::WORKFLOW)->getIndex();
937         int nbWritten = indexToWrite.numElements();
938
939         CArray<double,1> writtenLat, writtenLon;
940         CArray<double,2> writtenBndsLat, writtenBndsLon;
941
942         writtenLat.resize(nbWritten);
943         writtenLon.resize(nbWritten);
944         for (int idx = 0; idx < nbWritten; ++idx)
945         {
946           writtenLat(idx) = domain->latvalue(indexToWrite(idx));
947           writtenLon(idx) = domain->lonvalue(indexToWrite(idx));
948         }
949   
950         int nvertex = domain->nvertex, idx;
951        if (nvertex>1)
952         {
953           writtenBndsLat.resize(nvertex, nbWritten);
954           writtenBndsLon.resize(nvertex, nbWritten);
955           CArray<double,2>& boundslat = domain->bounds_latvalue;
956           CArray<double,2>& boundslon = domain->bounds_lonvalue;
957           for (idx = 0; idx < nbWritten; ++idx)
958             for (int nv = 0; nv < nvertex; ++nv)
959             {
960                writtenBndsLat(nv, idx) = boundslat(nv, int(indexToWrite(idx)));
961                writtenBndsLon(nv, idx) = boundslon(nv, int(indexToWrite(idx)));
962             }
963         }
964         domain->assignMesh(domainName, domain->nvertex);
965         //CContextServer* server=CContext::getCurrent()->server ;
966         //domain->mesh->createMeshEpsilon(server->intraComm, writtenLon, writtenLat, writtenBndsLon, writtenBndsLat);
967         MPI_Comm intraComm =CContext::getCurrent()->getIntraComm() ;
968         domain->mesh->createMeshEpsilon(intraComm, writtenLon, writtenLat, writtenBndsLon, writtenBndsLat);
969       }
970
971     }
972   }
973   CATCH_DUMP_ATTR
974
975   void CFile::sendGridOfEnabledFields()
976   TRY
977   { 
978     int size = this->enabledFields.size();
979     for (int i = 0; i < size; ++i)
980     {
981       this->enabledFields[i]->sendGridOfEnabledFields();
982     }
983   }
984   CATCH_DUMP_ATTR
985
986
987   /*!
988     Prefetching the data for enabled fields read from file.
989   */
990   void CFile::prefetchEnabledReadModeFields(void)
991   TRY
992   {
993     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
994       return;
995
996     int size = this->enabledFields.size();
997     for (int i = 0; i < size; ++i)
998       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
999   }
1000   CATCH_DUMP_ATTR
1001
1002   /*!
1003     Do all post timestep operations for enabled fields in read mode:
1004      - Prefetch the data read from file when needed
1005   */
1006   void CFile::doPostTimestepOperationsForEnabledReadModeFields(void)
1007   TRY
1008   {
1009     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
1010       return;
1011
1012     int size = this->enabledFields.size();
1013     for (int i = 0; i < size; ++i)
1014     {
1015       this->enabledFields[i]->sendReadDataRequestIfNeeded();
1016     }
1017   }
1018   CATCH_DUMP_ATTR
1019
1020   void CFile::solveFieldRefInheritance(bool apply)
1021   TRY
1022   {
1023      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
1024      std::vector<CField*> allF = this->getAllFields();
1025      for (unsigned int i = 0; i < allF.size(); i++)
1026         allF[i]->solveRefInheritance(apply);
1027   }
1028   CATCH_DUMP_ATTR
1029
1030   //----------------------------------------------------------------
1031
1032   /*!
1033   \brief Add a field into file.
1034      A field is added into file and it will be written out if the file is enabled and
1035   level of this field is smaller than level_output. A new field won't be created if one
1036   with id has already existed
1037   \param [in] id String identity of new field
1038   \return Pointer to added (or already existed) field
1039   */
1040   CField* CFile::addField(const string& id)
1041   TRY
1042   {
1043     return vFieldGroup->createChild(id);
1044   }
1045   CATCH_DUMP_ATTR
1046
1047   /*!
1048   \brief Add a field group into file.
1049      A field group is added into file and it will play a role as parents for fields.
1050   A new field group won't be created if one with id has already existed
1051   \param [in] id String identity of new field group
1052   \return Pointer to added (or already existed) field group
1053   */
1054   CFieldGroup* CFile::addFieldGroup(const string& id)
1055   TRY
1056   {
1057     return vFieldGroup->createChildGroup(id);
1058   }
1059   CATCH_DUMP_ATTR
1060
1061   /*!
1062   \brief Add a variable into file.
1063      A variable is added into file and if one with id has already existed, pointer to
1064   it will be returned.
1065      Variable as long as attributes are information container of file.
1066   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
1067   to fill in (extra) information for a file.
1068   \param [in] id String identity of new variable
1069   \return Pointer to added (or already existed) variable
1070   */
1071   CVariable* CFile::addVariable(const string& id)
1072   TRY
1073   {
1074     return vVariableGroup->createChild(id);
1075   }
1076   CATCH_DUMP_ATTR
1077
1078   /*!
1079   \brief Add a variable group into file.
1080      A variable group is added into file and it will play a role as parents for variables.
1081   A new variable group won't be created if one with id has already existed
1082   \param [in] id String identity of new variable group
1083   \return Pointer to added (or already existed) variable group
1084   */
1085   CVariableGroup* CFile::addVariableGroup(const string& id)
1086   TRY
1087   {
1088     return vVariableGroup->createChildGroup(id);
1089   }
1090   CATCH_DUMP_ATTR
1091
1092   void CFile::getWriterServicesId(bool defaultUsingServer2_, const string& defaultPoolWriterId_, const string& defaultWriterId_, const string& defaultPoolGathererId_, const string& defaultGathererId_,
1093                                   bool& usingServer2, string& poolWriterId, string& writerId, string& poolGathererId, string& gathererId)
1094   {
1095     usingServer2 = defaultUsingServer2_ ;
1096     poolWriterId = defaultPoolWriterId_ ;
1097     writerId = defaultWriterId_ ;
1098     poolGathererId = defaultPoolGathererId_ ;
1099     gathererId = defaultGathererId_ ;
1100
1101     if (!using_server2.isEmpty()) usingServer2 = using_server2;
1102     if (!pool_writer.isEmpty()) poolWriterId = pool_writer ;
1103     if (!writer.isEmpty()) writerId = writer;
1104     if (!pool_gatherer.isEmpty()) poolGathererId = pool_gatherer;
1105     if (!gatherer.isEmpty()) gathererId = gatherer;
1106   }
1107
1108   void CFile::getReaderServicesId(const string& defaultPoolReaderId_, const string& defaultReaderId_, string& poolReaderId, string& readerId)
1109   {
1110     poolReaderId = defaultPoolReaderId_ ;
1111     readerId = defaultReaderId_ ;
1112   
1113     if (!pool_reader.isEmpty()) poolReaderId = pool_reader ;
1114     if (!reader.isEmpty()) readerId = reader;
1115   }
1116
1117   void CFile::setContextClient(const string& defaultPoolId, const string& defaultServiceId, int partitionId)
1118   TRY
1119   {
1120     CContext* context = CContext::getCurrent();
1121     vector<CContextClient*> clients = context->getContextClient(defaultPoolId, defaultServiceId) ;
1122     setContextClient(clients[partitionId]) ;
1123   }
1124   CATCH_DUMP_ATTR
1125
1126
1127   void CFile::setContextClient(CContextClient* newContextClient)
1128   TRY
1129   {
1130     client = newContextClient;
1131     size_t size = this->enabledFields.size();
1132     for (size_t i = 0; i < size; ++i)
1133     {
1134       this->enabledFields[i]->setContextClient(newContextClient);
1135     }
1136   }
1137   CATCH_DUMP_ATTR
1138
1139   CContextClient* CFile::getContextClient()
1140   TRY
1141   {
1142     return client;
1143   }
1144   CATCH_DUMP_ATTR
1145
1146   
1147   /*!
1148   \brief Send a message to create a field on server side
1149   \param[in] id String identity of field that will be created on server
1150   */
1151   void CFile::sendAddField(const string& id, CContextClient* client)
1152   TRY
1153   {
1154      sendAddItem(id, EVENT_ID_ADD_FIELD, client);
1155   }
1156   CATCH_DUMP_ATTR
1157
1158   /*!
1159   \brief Send a message to create a field group on server side
1160   \param[in] id String identity of field group that will be created on server
1161   */
1162   void CFile::sendAddFieldGroup(const string& id, CContextClient* client)
1163   TRY
1164   {
1165      sendAddItem(id, (int)EVENT_ID_ADD_FIELD_GROUP, client);
1166   }
1167   CATCH_DUMP_ATTR
1168
1169   /*!
1170   \brief Receive a message annoucing the creation of a field on server side
1171   \param[in] event Received event
1172   */
1173   void CFile::recvAddField(CEventServer& event)
1174   TRY
1175   {
1176
1177      CBufferIn* buffer = event.subEvents.begin()->buffer;
1178      string id;
1179      *buffer>>id;
1180      get(id)->recvAddField(*buffer);
1181   }
1182   CATCH
1183
1184   /*!
1185   \brief Receive a message annoucing the creation of a field on server side
1186   \param[in] buffer Buffer containing message
1187   */
1188   void CFile::recvAddField(CBufferIn& buffer)
1189   TRY
1190   {
1191      string id;
1192      buffer>>id;
1193      addField(id);
1194   }
1195   CATCH_DUMP_ATTR
1196
1197   /*!
1198   \brief Receive a message annoucing the creation of a field group on server side
1199   \param[in] event Received event
1200   */
1201   void CFile::recvAddFieldGroup(CEventServer& event)
1202   TRY
1203   {
1204
1205      CBufferIn* buffer = event.subEvents.begin()->buffer;
1206      string id;
1207      *buffer>>id;
1208      get(id)->recvAddFieldGroup(*buffer);
1209   }
1210   CATCH
1211
1212   /*!
1213   \brief Receive a message annoucing the creation of a field group on server side
1214   \param[in] buffer Buffer containing message
1215   */
1216   void CFile::recvAddFieldGroup(CBufferIn& buffer)
1217   TRY
1218   {
1219      string id;
1220      buffer>>id;
1221      addFieldGroup(id);
1222   }
1223   CATCH_DUMP_ATTR
1224
1225   /*!
1226   \brief Send messages to duplicate all variables on server side
1227      Because each variable has also its attributes. So first thing to do is replicate
1228   all these attributes on server side. Because variable can have a value, the second thing
1229   is to duplicate this value on server, too.
1230   */
1231   void CFile::sendAddAllVariables(CContextClient* client)
1232   TRY
1233   {
1234     std::vector<CVariable*> allVar = getAllVariables();
1235     std::vector<CVariable*>::const_iterator it = allVar.begin();
1236     std::vector<CVariable*>::const_iterator itE = allVar.end();
1237
1238     for (; it != itE; ++it)
1239     {
1240       this->sendAddVariable((*it)->getId(), client);
1241       (*it)->sendAllAttributesToServer(client);
1242       (*it)->sendValue(client);
1243     }
1244   }
1245   CATCH_DUMP_ATTR
1246
1247   /*!
1248   \brief Send a message to create a variable group on server side
1249   \param[in] id String identity of variable group that will be created on server
1250   \param [in] client client to which we will send this adding action
1251   */
1252   void CFile::sendAddVariableGroup(const string& id, CContextClient* client)
1253   TRY
1254   {
1255      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1256   }
1257   CATCH_DUMP_ATTR
1258
1259   /*
1260     Send message to add a variable into a file within a certain client
1261     \param [in] id String identity of a variable
1262     \param [in] client client to which we will send this adding action
1263   */
1264   void CFile::sendAddVariable(const string& id, CContextClient* client)
1265   TRY
1266   {
1267      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1268   }
1269   CATCH_DUMP_ATTR
1270
1271   /*!
1272   \brief Receive a message annoucing the creation of a variable on server side
1273   \param[in] event Received event
1274   */
1275   void CFile::recvAddVariable(CEventServer& event)
1276   TRY
1277   {
1278      CBufferIn* buffer = event.subEvents.begin()->buffer;
1279      string id;
1280      *buffer>>id;
1281      get(id)->recvAddVariable(*buffer);
1282   }
1283   CATCH
1284
1285   /*!
1286   \brief Receive a message annoucing the creation of a variable on server side
1287   \param[in] buffer Buffer containing message
1288   */
1289   void CFile::recvAddVariable(CBufferIn& buffer)
1290   TRY
1291   {
1292      string id;
1293      buffer>>id;
1294      addVariable(id);
1295   }
1296   CATCH_DUMP_ATTR
1297
1298   /*!
1299   \brief Receive a message annoucing the creation of a variable group on server side
1300   \param[in] event Received event
1301   */
1302   void CFile::recvAddVariableGroup(CEventServer& event)
1303   TRY
1304   {
1305
1306      CBufferIn* buffer = event.subEvents.begin()->buffer;
1307      string id;
1308      *buffer>>id;
1309      get(id)->recvAddVariableGroup(*buffer);
1310   }
1311   CATCH
1312
1313   /*!
1314   \brief Receive a message annoucing the creation of a variable group on server side
1315   \param[in] buffer Buffer containing message
1316   */
1317   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1318   TRY
1319   {
1320      string id;
1321      buffer>>id;
1322      addVariableGroup(id);
1323   }
1324   CATCH_DUMP_ATTR
1325
1326   /*!
1327     \brief Sending all active (enabled) fields from client to server.
1328   Each field is identified uniquely by its string identity. Not only should we
1329   send the id to server but also we need to send ids of reference domain and reference axis.
1330   With these two id, it's easier to make reference to grid where all data should be written.
1331   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1332   */
1333   void CFile::sendEnabledFields(CContextClient* client)
1334   TRY
1335   {
1336     size_t size = this->enabledFields.size();
1337     for (size_t i = 0; i < size; ++i)
1338     {
1339       CField* field = this->enabledFields[i];
1340       this->sendAddField(field->getId(), client);
1341       field->checkTimeAttributes();
1342       field->sendAllAttributesToServer(client);
1343       field->sendAddAllVariables(client);
1344     }
1345   }
1346   CATCH_DUMP_ATTR
1347
1348
1349 
1350   /*!
1351    * Send file attribute, related variable and chield field tree to a given file server.
1352    * \param[in] client : the context client where to send file
1353    */
1354   void CFile::sendFileToFileServer(CContextClient* client)
1355   TRY
1356   {
1357     if (sendFileToFileServer_done_.count(client)!=0) return ;
1358     else sendFileToFileServer_done_.insert(client) ;
1359     
1360     StdString fileDefRoot("file_definition");
1361     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1362     cfgrpPtr->sendCreateChild(this->getId(), client);
1363     this->sendAllAttributesToServer(client);
1364     this->sendAddAllVariables(client);
1365     for(auto field : enabledFields) this->sendAddField(field->getId(), client);
1366   }
1367   CATCH_DUMP_ATTR
1368   /*!
1369   \brief Dispatch event received from client
1370      Whenever a message is received in buffer of server, it will be processed depending on
1371   its event type. A new event type should be added in the switch list to make sure
1372   it processed on server side.
1373   \param [in] event: Received message
1374   */
1375   bool CFile::dispatchEvent(CEventServer& event)
1376   TRY
1377   {
1378      if (SuperClass::dispatchEvent(event)) return true;
1379      else
1380      {
1381        switch(event.type)
1382        {
1383           case EVENT_ID_ADD_FIELD :
1384             recvAddField(event);
1385             return true;
1386             break;
1387
1388           case EVENT_ID_ADD_FIELD_GROUP :
1389             recvAddFieldGroup(event);
1390             return true;
1391             break;
1392
1393            case EVENT_ID_ADD_VARIABLE :
1394             recvAddVariable(event);
1395             return true;
1396             break;
1397
1398           case EVENT_ID_ADD_VARIABLE_GROUP :
1399             recvAddVariableGroup(event);
1400             return true;
1401             break;
1402           default :
1403              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1404           return false;
1405        }
1406      }
1407   }
1408   CATCH
1409
1410   ///--------------------------------------------------------------
1411   /*!
1412   */
1413   StdString CFile::dumpClassAttributes(void)
1414   {
1415     StdString str;
1416     CContext* context = CContext::getCurrent();
1417     str.append("context=\"");
1418     str.append(context->getId());
1419     str.append("\"");
1420     str.append(" enabled fields=\"");
1421     int size = this->enabledFields.size();
1422     for (int i = 0; i < size; ++i)
1423     {
1424       str.append(this->enabledFields[i]->getId());
1425       str.append(" ");
1426     }
1427     str.append("\"");
1428     return str;
1429   }
1430
1431   ///---------------------------------------------------------------
1432
1433} // namespace xios
Note: See TracBrowser for help on using the repository browser.