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

Last change on this file since 2628 was 2628, checked in by jderouillat, 6 weeks ago

New timers integration/reporting

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