source: XIOS3/dev/XIOS_ATTACHED/src/node/file.cpp @ 2482

Last change on this file since 2482 was 2482, checked in by ymipsl, 15 months ago

First guess in supression of attached mode replaced by online reader and write filters

YM

  • 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.3 KB
RevLine 
[219]1#include "file.hpp"
2
[352]3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
[219]6#include "object_factory.hpp"
[300]7#include "context.hpp"
8#include "context_server.hpp"
9#include "nc4_data_output.hpp"
[599]10#include "nc4_data_input.hpp"
[318]11#include "calendar_util.hpp"
12#include "date.hpp"
[352]13#include "message.hpp"
14#include "type.hpp"
[591]15#include "xios_spl.hpp"
[1158]16#include "context_client.hpp"
[382]17#include "mpi.hpp"
[1158]18#include "timer.hpp"
[1234]19#include "server.hpp"
[219]20
[335]21namespace xios {
[509]22
[878]23   /// ////////////////////// Dfinitions ////////////////////// ///
[219]24
25   CFile::CFile(void)
26      : CObjectTemplate<CFile>(), CFileAttributes()
[1639]27      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
[2458]28      , isOpen(false),  checkRead(false), allZoneEmpty(false)
[509]29   {
[957]30     setVirtualFieldGroup(CFieldGroup::create(getId() + "_virtual_field_group"));
31     setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group"));
[472]32   }
[219]33
34   CFile::CFile(const StdString & id)
35      : CObjectTemplate<CFile>(id), CFileAttributes()
[1639]36      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
[2458]37      , isOpen(false), checkRead(false), allZoneEmpty(false)
[509]38    {
[957]39      setVirtualFieldGroup(CFieldGroup::create(getId() + "_virtual_field_group"));
40      setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group"));
[472]41    }
[219]42
43   CFile::~CFile(void)
44   { /* Ne rien faire de plus */ }
45
46   ///---------------------------------------------------------------
[509]47  //! Get name of file
[219]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   //----------------------------------------------------------------
[773]53
[1158]54   const StdString CFile::getFileOutputName(void) const
[1622]55   TRY
[773]56   {
[1158]57     return (name.isEmpty() ? getId() : name) + (name_suffix.isEmpty() ? StdString("") :  name_suffix.getValue());
[773]58   }
[1622]59   CATCH
[773]60
61   //----------------------------------------------------------------
[509]62   /*!
[599]63   \brief Get data writer object.
[509]64   Each enabled file in xml represents a physical netcdf file.
[599]65   This function allows to access the data writer object.
66   \return data writer object.
[509]67   */
[1542]68   std::shared_ptr<CDataOutput> CFile::getDataOutput(void) const
[1622]69   TRY
[219]70   {
[599]71      return data_out;
[219]72   }
[1622]73   CATCH
[219]74
[509]75   /*!
[599]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   */
[1542]81   std::shared_ptr<CDataInput> CFile::getDataInput(void) const
[1622]82   TRY
[599]83   {
84      return data_in;
85   }
[1622]86   CATCH
[599]87
88   /*!
[509]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   */
[347]95   CFieldGroup* CFile::getVirtualFieldGroup(void) const
[1622]96   TRY
[219]97   {
98      return (this->vFieldGroup);
99   }
[1622]100   CATCH
[219]101
[509]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   */
[472]109   CVariableGroup* CFile::getVirtualVariableGroup(void) const
[1622]110   TRY
[472]111   {
112      return (this->vVariableGroup);
113   }
[1622]114   CATCH
[472]115
[509]116   //! Get all fields of a file
[347]117   std::vector<CField*> CFile::getAllFields(void) const
[1622]118   TRY
[219]119   {
120      return (this->vFieldGroup->getAllChildren());
121   }
[1622]122   CATCH
[509]123
124   //! Get all variables of a file
[472]125   std::vector<CVariable*> CFile::getAllVariables(void) const
[1622]126   TRY
[472]127   {
128      return (this->vVariableGroup->getAllChildren());
129   }
[1622]130   CATCH
[219]131
132   //----------------------------------------------------------------
[509]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,
[347]143                                                int default_level,
144                                                bool default_enabled)
[1622]145   TRY
[219]146   {
[1869]147      if (!this->enabledFields.empty()) return (this->enabledFields);
[219]148
[1869]149      const int _outputlevel = (!output_level.isEmpty()) ? output_level.getValue() : default_outputlevel;
[347]150      std::vector<CField*>::iterator it;
[219]151      this->enabledFields = this->getAllFields();
152
[347]153      std::vector<CField*> newEnabledFields;
[509]154
[651]155      for ( it = this->enabledFields.begin(); it != this->enabledFields.end(); it++ )
[219]156      {
[878]157         if (!(*it)->enabled.isEmpty()) // Si l'attribut 'enabled' est dfini ...
[219]158         {
[300]159            if (! (*it)->enabled.getValue()) continue;
[219]160         }
[878]161         else // Si l'attribut 'enabled' n'est pas dfini ...
[219]162         {
[651]163            if (!default_enabled) continue;
[219]164         }
165
[878]166         if (!(*it)->level.isEmpty()) // Si l'attribut 'level' est dfini ...
[219]167         {
[651]168            if ((*it)->level.getValue() > _outputlevel) continue;
[219]169         }
[878]170         else // Si l'attribut 'level' n'est pas dfini ...
[219]171         {
[651]172            if (default_level > _outputlevel) continue;
[219]173         }
[509]174
[651]175         newEnabledFields.push_back(*it);
[219]176      }
[651]177      enabledFields = newEnabledFields;
[219]178
179      return (this->enabledFields);
180   }
[1622]181   CATCH_DUMP_ATTR
[219]182
[2482]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
[219]190   //----------------------------------------------------------------
[509]191   //! Change virtual field group to a new one
[347]192   void CFile::setVirtualFieldGroup(CFieldGroup* newVFieldGroup)
[1622]193   TRY
[509]194   {
195      this->vFieldGroup = newVFieldGroup;
[219]196   }
[1622]197   CATCH_DUMP_ATTR
[219]198
[509]199   //! Change virtual variable group to new one
[472]200   void CFile::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
[1622]201   TRY
[509]202   {
203      this->vVariableGroup = newVVariableGroup;
[472]204   }
[1622]205   CATCH_DUMP_ATTR
[472]206
[219]207   //----------------------------------------------------------------
[318]208   bool CFile::isSyncTime(void)
[1622]209   TRY
[318]210   {
[651]211     CContext* context = CContext::getCurrent();
212     const CDate& currentDate = context->calendar->getCurrentDate();
[538]213     if (!sync_freq.isEmpty())
[318]214     {
[651]215       if (lastSync + sync_freq.getValue() < currentDate)
[318]216       {
[651]217         lastSync = currentDate;
218         return true;
[318]219        }
220      }
[651]221      return false;
[318]222    }
[1622]223    CATCH_DUMP_ATTR
[509]224
225   //! Initialize a file in order to write into it
[1232]226   void CFile::initWrite(void)
[1622]227   TRY
[321]228   {
[651]229      CContext* context = CContext::getCurrent();
230      const CDate& currentDate = context->calendar->getCurrentDate();
[509]231
[651]232      lastSync  = currentDate;
233      lastSplit = currentDate;
[702]234      if (!split_freq.isEmpty())
235      {
[1316]236        StdString keySuffix("CFile::"+getFileOutputName()+"::") ; 
[1158]237        if (context->registryIn->foundKey(keySuffix+"splitStart") && context->registryIn->foundKey(keySuffix+"splitEnd"))
[702]238        {
239          CDate savedSplitStart(*context->getCalendar()), savedSplitEnd(*context->getCalendar());
[1158]240          context->registryIn->getKey(keySuffix+"splitStart", savedSplitStart);
241          context->registryIn->getKey(keySuffix+"splitEnd",   savedSplitEnd);
[702]242
243          if (savedSplitStart <= lastSplit && lastSplit <= savedSplitEnd)
244            lastSplit = savedSplitStart;
245        }
246      }
[1232]247      isOpen = false;     
[379]248
[1009]249      set<StdString> setAxis;
250      set<StdString> setDomains;
[379]251
252      std::vector<CField*>::iterator it, end = this->enabledFields.end();
[609]253      for (it = this->enabledFields.begin(); it != end; it++)
[379]254      {
[1232]255         CField* field = *it;         
[1869]256         std::vector<CAxis*> vecAxis = field->getGrid()->getAxis();
[609]257         for (size_t i = 0; i < vecAxis.size(); ++i)
[1009]258           setAxis.insert(vecAxis[i]->getAxisOutputName());
[1869]259         std::vector<CDomain*> vecDomains = field->getGrid()->getDomains();
[609]260         for (size_t i = 0; i < vecDomains.size(); ++i)
[1009]261           setDomains.insert(vecDomains[i]->getDomainOutputName());
[379]262      }
[609]263      nbAxis = setAxis.size();
264      nbDomains = setDomains.size();
[379]265
[509]266      // create sub communicator for file
[2400]267      if (type == CFile::type_attr::multiple_file)
268      {
269        createSubComFile();
270      }
271      else
272      {
273        // NetCDF runs now write of null data
274        MPI_Comm_dup(context->intraComm_, &fileComm) ;
275      }
[692]276
[802]277      if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
[321]278    }
[1622]279    CATCH_DUMP_ATTR
[509]280
[1232]281    //! Initialize a file in order to write into it
282    void CFile::initRead(void)
[1622]283    TRY
[1232]284    {
[1872]285      CContext* context = CContext::getCurrent();
[1232]286      if (checkRead) return;
[1872]287      //createSubComFile();
288      allZoneEmpty = false; 
289      MPI_Comm_dup(context->intraComm_, &fileComm) ;
[1232]290      checkRead = true;
291    }
[1622]292    CATCH_DUMP_ATTR
[1232]293
294    /*!
295      Create a sub communicator in which processes participate in reading/opening file
[2149]296      Seems to be deprecated (allZoneEmpty too, which is always false)
[1232]297    */
298    void CFile::createSubComFile()
[1622]299    TRY
[1232]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;
[1869]309         bool nullGrid = (nullptr == field->getGrid());
310         allZoneEmpty &= nullGrid ? false : !field->getGrid()->doGridHaveDataToWrite();
[1232]311      }
312
313      int color = allZoneEmpty ? 0 : 1;
[1853]314      MPI_Comm_split(context->intraComm_, color, context->intraCommRank_, &fileComm);
[1639]315      if (allZoneEmpty) MPI_Comm_free(&fileComm);
[1232]316    }
[1622]317    CATCH_DUMP_ATTR
[1232]318
[1136]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)
[1622]325    TRY
[321]326    {
[1054]327      CContext* context = CContext::getCurrent();
[1961]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(); 
[1136]337    }
[1622]338    CATCH_DUMP_ATTR
[1136]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)
[1622]347    TRY
[1136]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
[1761]352
[1871]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//      {
[1136]357        if (!mode.isEmpty() && mode.getValue() == mode_attr::read)
[1054]358        {
[1158]359          CTimer::get("Files : open headers").resume();
[1232]360         
361          if (!isOpen) openInReadMode();
362
[1158]363          CTimer::get("Files : open headers").suspend();
[1054]364        }
[1136]365        //checkSplit(); // Really need for reading?
[1871]366 //     }
[321]367    }
[1622]368    CATCH_DUMP_ATTR
[509]369
370    /*!
[1232]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()
[1622]375    TRY
[1232]376    {
377      return allZoneEmpty;
378    }
[1622]379    CATCH_DUMP_ATTR
[1232]380
381    /*!
[509]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    */
[321]387   bool CFile::checkSync(void)
[1622]388   TRY
[321]389   {
[651]390     CContext* context = CContext::getCurrent();
391     const CDate& currentDate = context->calendar->getCurrentDate();
[538]392     if (!sync_freq.isEmpty())
[321]393     {
[651]394       if (lastSync + sync_freq.getValue() <= currentDate)
[321]395       {
[651]396         lastSync = currentDate;
397         data_out->syncFile();
398         return true;
[321]399        }
400      }
[651]401      return false;
[321]402    }
[1622]403   CATCH_DUMP_ATTR
[509]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    */
[321]411    bool CFile::checkSplit(void)
[1622]412    TRY
[321]413    {
[651]414      CContext* context = CContext::getCurrent();
415      const CDate& currentDate = context->calendar->getCurrentDate();
[538]416      if (!split_freq.isEmpty())
[321]417      {
[651]418        if (currentDate > lastSplit + split_freq.getValue())
[321]419        {
[651]420          lastSplit = lastSplit + split_freq.getValue();
[347]421          std::vector<CField*>::iterator it, end = this->enabledFields.end();
[1961]422/*          for (it = this->enabledFields.begin(); it != end; it++)
[599]423          {
424            (*it)->resetNStep();
425            (*it)->resetNStepMax();
[1961]426          }*/
[599]427          if (mode.isEmpty() || mode.getValue() == mode_attr::write)
[651]428            createHeader();
[599]429          else
430            openInReadMode();
[651]431          return true;
[321]432        }
433      }
[651]434      return false;
[321]435    }
[1622]436    CATCH_DUMP_ATTR
[509]437
[1961]438
[509]439   /*!
440   \brief Create header of netcdf file
441   There are some information to fill in header of each netcdf.
442   */
[300]443   void CFile::createHeader(void)
[1622]444   TRY
[219]445   {
[651]446      CContext* context = CContext::getCurrent();
[1853]447     
[1232]448      if (!allZoneEmpty)
[219]449      {
[773]450         StdString filename = getFileOutputName();
[875]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 ;
[920]462         bool hasEndDate=false ;
463         bool hasSplit = (!split_freq.isEmpty());
[875]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 ;
[920]489           if (hasSplit) firstPart +="_";
[875]490           middlePart="-" ;
491         }
[920]492   
[300]493         StdOStringStream oss;
[538]494
[431]495         if (!split_freq.isEmpty())
496         {
[1201]497           CDate split_start ;
498           CDate splitEnd ;
499           if (!split_start_offset.isEmpty()) split_start=lastSplit + split_start_offset ;
500           else split_start=lastSplit ;
[702]501
[1201]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
[651]512           string splitFormat;
[431]513           if (split_freq_format.isEmpty())
514           {
[1516]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";
[538]522             else splitFormat = "%y";
[431]523           }
[651]524           else splitFormat = split_freq_format;
[702]525
[875]526           oss << firstPart ;
[1201]527           if (hasStartDate) oss << split_start.getStr(splitFormat) ;
[875]528           oss << middlePart ;
529           if (hasEndDate) oss << splitEnd.getStr(splitFormat);
530           oss << lastPart ;
[702]531
[1316]532           StdString keySuffix("CFile::"+getFileOutputName()+"::") ; 
[1158]533           context->registryOut->setKey(keySuffix+"splitStart", lastSplit);
534           context->registryOut->setKey(keySuffix+"splitEnd",   splitEnd);
[431]535         }
[875]536         else oss<<firstPart<<lastPart ;
[509]537
[528]538        bool append = !this->append.isEmpty() && this->append.getValue();
[567]539
[517]540         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
[878]541         bool useCFConvention = convention.isEmpty() || convention == convention_attr::CF;
[517]542
[651]543         bool multifile = true;
[300]544         if (!type.isEmpty())
545         {
[651]546           if (type == type_attr::one_file) multifile = false;
547           else if (type == type_attr::multiple_file) multifile = true;
[379]548
[509]549         }
[379]550#ifndef USING_NETCDF_PAR
551         if (!multifile)
552         {
[651]553            info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
554            multifile = true;
[379]555          }
556#endif
[509]557         if (multifile)
[300]558         {
[651]559            int commSize, commRank;
[1639]560            MPI_Comm_size(fileComm, &commSize);
561            MPI_Comm_rank(fileComm, &commRank);
[509]562
[1853]563            if (context->intraCommSize_ > 1)
[375]564            {
[651]565              oss << "_" ;
566              int width=0; int n = commSize-1;
567              while (n != 0) { n = n / 10; width++;}
[509]568              if (!min_digits.isEmpty())
[651]569                if (width < min_digits) width = min_digits;
570              oss.width(width);
571              oss.fill('0');
572              oss << right << commRank;
[375]573            }
[300]574         }
575         oss << ".nc";
576
[526]577         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
578
579         if (isOpen) data_out->closeFile();
580
[1542]581        data_out = std::shared_ptr<CDataOutput>(new CNc4DataOutput(this, oss.str(), append, useClassicFormat, useCFConvention,
[802]582                                                              fileComm, multifile, isCollective, time_counter_name));
[528]583        isOpen = true;
[300]584
[528]585        data_out->writeFile(CFile::get(this));
586
[1494]587        if (!useCFConvention) sortEnabledFieldsForUgrid();
588
[528]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          {
[347]595            CField* field = *it;
[300]596            this->data_out->writeFieldGrid(field);
[528]597          }
598          this->data_out->writeTimeDimension();
[509]599
[528]600          for (it = this->enabledFields.begin(); it != end; it++)
601          {
[347]602            CField* field = *it;
[1158]603            this->data_out->writeFieldTimeAxis(field);
604          }
605         
606          for (it = this->enabledFields.begin(); it != end; it++)
607          {
608            CField* field = *it;
[300]609            this->data_out->writeField(field);
[528]610          }
[509]611
[651]612          vector<CVariable*> listVars = getAllVariables();
[528]613          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
614            this->data_out->writeAttribute(*it);
[509]615
[528]616          this->data_out->definition_end();
617        }
[1158]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        }
[219]628      }
629   }
[1622]630   CATCH_DUMP_ATTR
[219]631
[599]632  /*!
633  \brief Open an existing NetCDF file in read-only mode
634  */
[1232]635  void CFile::openInReadMode()
[1622]636  TRY
[599]637  {
638    CContext* context = CContext::getCurrent();
[1639]639    MPI_Comm readComm = this->fileComm;
[599]640
[1232]641    if (!allZoneEmpty)
[599]642    {
[773]643      StdString filename = getFileOutputName();
[599]644      StdOStringStream oss;
645      oss << filename;
646
647      if (!split_freq.isEmpty())
648      {
649        string splitFormat;
650        if (split_freq_format.isEmpty())
651        {
[1516]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";
[599]659          else splitFormat = "%y";
660        }
[651]661        else splitFormat = split_freq_format;
662        oss << "_" << lastSplit.getStr(splitFormat)
663        << "-" << (lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
[599]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;
[1639]682        MPI_Comm_size(readComm, &commSize);
683        MPI_Comm_rank(readComm, &commRank);
[599]684
[1853]685        if (context->intraCommSize_ > 1)
[599]686        {
[651]687          oss << "_";
[599]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;
[1485]700      bool readMetaDataPar = true;
[1853]701      if (context->getServiceType()==CServicesManager::CLIENT) readMetaDataPar = (read_metadata_par.isEmpty()) ? false : read_metadata_par;
[599]702
703      if (isOpen) data_out->closeFile();
[1486]704      bool ugridConvention = !convention.isEmpty() ? (convention == convention_attr::UGRID) : false;
705      if (time_counter_name.isEmpty())
[1542]706        data_in = std::shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective, readMetaDataPar, ugridConvention));
[1486]707      else
[1542]708        data_in = std::shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective, readMetaDataPar, ugridConvention, time_counter_name));
[599]709      isOpen = true;
710    }
711  }
[1622]712  CATCH_DUMP_ATTR
[599]713
[509]714   //! Close file
[286]715   void CFile::close(void)
[1622]716   TRY
[286]717   {
[1232]718     if (!allZoneEmpty)
[509]719       if (isOpen)
[321]720       {
[599]721         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
722          this->data_out->closeFile();
723         else
724          this->data_in->closeFile();
[1232]725        isOpen = false;
[321]726       }
[1639]727      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
[286]728   }
[1622]729   CATCH_DUMP_ATTR
730
[219]731   //----------------------------------------------------------------
732
[775]733   void CFile::readAttributesOfEnabledFieldsInReadMode()
[1622]734   TRY
[775]735   {
736     if (enabledFields.empty()) return;
737
738     // Just check file and try to open it
[805]739     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
740
[1136]741     checkReadFile();
[805]742
[775]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
[2002]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();
[775]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   }
[1622]767   CATCH_DUMP_ATTR
[775]768
[1871]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   }
[509]778   /*!
779   \brief Parse xml file and write information into file object
780   \param [in] node xmld node corresponding in xml file
781   */
[219]782   void CFile::parse(xml::CXMLNode & node)
[1622]783   TRY
[219]784   {
785      SuperClass::parse(node);
[509]786
[472]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);
[651]793        } while (node.goToNextElement());
[472]794        node.goToParentElement();
[219]795      }
[1622]796   }
797   CATCH_DUMP_ATTR
[472]798
[219]799   //----------------------------------------------------------------
800
[509]801   /*!
802   \brief Represent a file in form of string with all its info
803   \return String
804   */
[219]805   StdString CFile::toString(void) const
[1622]806   TRY
[219]807   {
808      StdOStringStream oss;
809
810      oss << "<" << CFile::GetName() << " ";
811      if (this->hasId())
812         oss << " id=\"" << this->getId() << "\" ";
813      oss << SuperClassAttribute::toString() << ">" << std::endl;
[347]814      if (this->getVirtualFieldGroup() != NULL)
[219]815         oss << *this->getVirtualFieldGroup() << std::endl;
816      oss << "</" << CFile::GetName() << " >";
817      return (oss.str());
818   }
[1622]819   CATCH
[219]820
821   //----------------------------------------------------------------
[509]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   */
[445]829   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
[1622]830   TRY
[219]831   {
[445]832      SuperClassAttribute::setAttributes(parent,apply);
[509]833      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
[472]834      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
[219]835   }
[1622]836   CATCH_DUMP_ATTR
[219]837
838   //----------------------------------------------------------------
839
[1025]840   void CFile::checkGridOfEnabledFields()
[1622]841   TRY
[1025]842   { 
843     int size = this->enabledFields.size();
844     for (int i = 0; i < size; ++i)
845     {
846       this->enabledFields[i]->checkGridOfEnabledFields();
847     }
848   }
[1622]849   CATCH_DUMP_ATTR
[1025]850
[1239]851   void CFile::sendGridComponentOfEnabledFields()
[1622]852   TRY
[1239]853   { 
854     int size = this->enabledFields.size();
855     for (int i = 0; i < size; ++i)
856     {
857       this->enabledFields[i]->sendGridComponentOfEnabledFields();
858     }
859   }
[1622]860   CATCH_DUMP_ATTR
[1239]861
[1494]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()
[1622]867   TRY
[1494]868   {
869     int size = this->enabledFields.size();
870     std::vector<int> domainNvertices;
871     std::vector<StdString> domainNames;
[2409]872     std::map<string, tuple<set<CDomain*>,set<CDomain*>,set<CDomain*>>> registeredDomains ;
[1494]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       }
[2409]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]) ;
[1494]919     }
[2409]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     }
[1494]972   }
[1622]973   CATCH_DUMP_ATTR
[1494]974
[1025]975   void CFile::sendGridOfEnabledFields()
[1622]976   TRY
[1025]977   { 
978     int size = this->enabledFields.size();
979     for (int i = 0; i < size; ++i)
980     {
981       this->enabledFields[i]->sendGridOfEnabledFields();
982     }
983   }
[1622]984   CATCH_DUMP_ATTR
[1025]985
[823]986
987   /*!
[598]988     Prefetching the data for enabled fields read from file.
989   */
990   void CFile::prefetchEnabledReadModeFields(void)
[1622]991   TRY
[598]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)
[1934]998       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
[598]999   }
[1622]1000   CATCH_DUMP_ATTR
[598]1001
1002   /*!
[1318]1003     Do all post timestep operations for enabled fields in read mode:
1004      - Prefetch the data read from file when needed
[598]1005   */
[1318]1006   void CFile::doPostTimestepOperationsForEnabledReadModeFields(void)
[1622]1007   TRY
[598]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)
[1318]1014     {
[598]1015       this->enabledFields[i]->sendReadDataRequestIfNeeded();
[1318]1016     }
[598]1017   }
[1622]1018   CATCH_DUMP_ATTR
[598]1019
[445]1020   void CFile::solveFieldRefInheritance(bool apply)
[1622]1021   TRY
[219]1022   {
[878]1023      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
[347]1024      std::vector<CField*> allF = this->getAllFields();
[219]1025      for (unsigned int i = 0; i < allF.size(); i++)
[445]1026         allF[i]->solveRefInheritance(apply);
[219]1027   }
[1622]1028   CATCH_DUMP_ATTR
[219]1029
1030   //----------------------------------------------------------------
1031
[509]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   */
[347]1040   CField* CFile::addField(const string& id)
[1622]1041   TRY
[300]1042   {
[651]1043     return vFieldGroup->createChild(id);
[300]1044   }
[1622]1045   CATCH_DUMP_ATTR
[219]1046
[509]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   */
[347]1054   CFieldGroup* CFile::addFieldGroup(const string& id)
[1622]1055   TRY
[300]1056   {
[651]1057     return vFieldGroup->createChildGroup(id);
[300]1058   }
[1622]1059   CATCH_DUMP_ATTR
[509]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   */
[472]1071   CVariable* CFile::addVariable(const string& id)
[1622]1072   TRY
[472]1073   {
[651]1074     return vVariableGroup->createChild(id);
[472]1075   }
[1622]1076   CATCH_DUMP_ATTR
[472]1077
[509]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   */
[472]1085   CVariableGroup* CFile::addVariableGroup(const string& id)
[1622]1086   TRY
[472]1087   {
[651]1088     return vVariableGroup->createChildGroup(id);
[472]1089   }
[1622]1090   CATCH_DUMP_ATTR
[509]1091
[2458]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
[1021]1127   void CFile::setContextClient(CContextClient* newContextClient)
[1622]1128   TRY
[1021]1129   {
1130     client = newContextClient;
[1294]1131     size_t size = this->enabledFields.size();
1132     for (size_t i = 0; i < size; ++i)
1133     {
1134       this->enabledFields[i]->setContextClient(newContextClient);
1135     }
[1021]1136   }
[1622]1137   CATCH_DUMP_ATTR
[1021]1138
1139   CContextClient* CFile::getContextClient()
[1622]1140   TRY
[1021]1141   {
1142     return client;
1143   }
[1622]1144   CATCH_DUMP_ATTR
[1021]1145
[2458]1146   
[509]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   */
[1021]1151   void CFile::sendAddField(const string& id, CContextClient* client)
[1622]1152   TRY
[1009]1153   {
[1021]1154      sendAddItem(id, EVENT_ID_ADD_FIELD, client);
[1009]1155   }
[1622]1156   CATCH_DUMP_ATTR
[1009]1157
[509]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   */
[1136]1162   void CFile::sendAddFieldGroup(const string& id, CContextClient* client)
[1622]1163   TRY
[1136]1164   {
1165      sendAddItem(id, (int)EVENT_ID_ADD_FIELD_GROUP, client);
1166   }
[1622]1167   CATCH_DUMP_ATTR
[1136]1168
1169   /*!
[509]1170   \brief Receive a message annoucing the creation of a field on server side
1171   \param[in] event Received event
1172   */
[300]1173   void CFile::recvAddField(CEventServer& event)
[1622]1174   TRY
[300]1175   {
[509]1176
[651]1177      CBufferIn* buffer = event.subEvents.begin()->buffer;
[300]1178      string id;
[651]1179      *buffer>>id;
1180      get(id)->recvAddField(*buffer);
[300]1181   }
[1622]1182   CATCH
[509]1183
1184   /*!
1185   \brief Receive a message annoucing the creation of a field on server side
1186   \param[in] buffer Buffer containing message
1187   */
[300]1188   void CFile::recvAddField(CBufferIn& buffer)
[1622]1189   TRY
[300]1190   {
[651]1191      string id;
1192      buffer>>id;
1193      addField(id);
[300]1194   }
[1622]1195   CATCH_DUMP_ATTR
[300]1196
[509]1197   /*!
1198   \brief Receive a message annoucing the creation of a field group on server side
1199   \param[in] event Received event
1200   */
[300]1201   void CFile::recvAddFieldGroup(CEventServer& event)
[1622]1202   TRY
[300]1203   {
[509]1204
[651]1205      CBufferIn* buffer = event.subEvents.begin()->buffer;
[300]1206      string id;
[651]1207      *buffer>>id;
1208      get(id)->recvAddFieldGroup(*buffer);
[300]1209   }
[1622]1210   CATCH
[509]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   */
[300]1216   void CFile::recvAddFieldGroup(CBufferIn& buffer)
[1622]1217   TRY
[300]1218   {
[651]1219      string id;
1220      buffer>>id;
1221      addFieldGroup(id);
[300]1222   }
[1622]1223   CATCH_DUMP_ATTR
[300]1224
[509]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   */
[1021]1231   void CFile::sendAddAllVariables(CContextClient* client)
[1622]1232   TRY
[1009]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     {
[1021]1240       this->sendAddVariable((*it)->getId(), client);
1241       (*it)->sendAllAttributesToServer(client);
1242       (*it)->sendValue(client);
[1009]1243     }
1244   }
[1622]1245   CATCH_DUMP_ATTR
[1009]1246
[509]1247   /*!
[1009]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
[1132]1250   \param [in] client client to which we will send this adding action
1251   */
1252   void CFile::sendAddVariableGroup(const string& id, CContextClient* client)
[1622]1253   TRY
[1132]1254   {
1255      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1256   }
[1622]1257   CATCH_DUMP_ATTR
[1132]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   */
[1021]1264   void CFile::sendAddVariable(const string& id, CContextClient* client)
[1622]1265   TRY
[472]1266   {
[1130]1267      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
[472]1268   }
[1622]1269   CATCH_DUMP_ATTR
[509]1270
1271   /*!
1272   \brief Receive a message annoucing the creation of a variable on server side
1273   \param[in] event Received event
1274   */
[472]1275   void CFile::recvAddVariable(CEventServer& event)
[1622]1276   TRY
[472]1277   {
[651]1278      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1279      string id;
[651]1280      *buffer>>id;
1281      get(id)->recvAddVariable(*buffer);
[472]1282   }
[1622]1283   CATCH
[509]1284
1285   /*!
1286   \brief Receive a message annoucing the creation of a variable on server side
1287   \param[in] buffer Buffer containing message
1288   */
[472]1289   void CFile::recvAddVariable(CBufferIn& buffer)
[1622]1290   TRY
[472]1291   {
[651]1292      string id;
1293      buffer>>id;
1294      addVariable(id);
[472]1295   }
[1622]1296   CATCH_DUMP_ATTR
[472]1297
[509]1298   /*!
1299   \brief Receive a message annoucing the creation of a variable group on server side
1300   \param[in] event Received event
1301   */
[472]1302   void CFile::recvAddVariableGroup(CEventServer& event)
[1622]1303   TRY
[472]1304   {
[509]1305
[651]1306      CBufferIn* buffer = event.subEvents.begin()->buffer;
[472]1307      string id;
[651]1308      *buffer>>id;
1309      get(id)->recvAddVariableGroup(*buffer);
[472]1310   }
[1622]1311   CATCH
[509]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   */
[472]1317   void CFile::recvAddVariableGroup(CBufferIn& buffer)
[1622]1318   TRY
[472]1319   {
[651]1320      string id;
1321      buffer>>id;
1322      addVariableGroup(id);
[472]1323   }
[1622]1324   CATCH_DUMP_ATTR
[472]1325
[509]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
[1136]1332   */
1333   void CFile::sendEnabledFields(CContextClient* client)
[1622]1334   TRY
[1009]1335   {
1336     size_t size = this->enabledFields.size();
1337     for (size_t i = 0; i < size; ++i)
1338     {
1339       CField* field = this->enabledFields[i];
[1021]1340       this->sendAddField(field->getId(), client);
[1405]1341       field->checkTimeAttributes();
[1021]1342       field->sendAllAttributesToServer(client);
1343       field->sendAddAllVariables(client);
[1009]1344     }
1345   }
[1622]1346   CATCH_DUMP_ATTR
[1009]1347
[1870]1348
1349 
[509]1350   /*!
[1870]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   /*!
[509]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   */
[300]1375   bool CFile::dispatchEvent(CEventServer& event)
[1622]1376   TRY
[300]1377   {
[651]1378      if (SuperClass::dispatchEvent(event)) return true;
[300]1379      else
1380      {
1381        switch(event.type)
1382        {
1383           case EVENT_ID_ADD_FIELD :
[651]1384             recvAddField(event);
1385             return true;
1386             break;
[509]1387
[300]1388           case EVENT_ID_ADD_FIELD_GROUP :
[651]1389             recvAddFieldGroup(event);
1390             return true;
1391             break;
[509]1392
[472]1393            case EVENT_ID_ADD_VARIABLE :
[651]1394             recvAddVariable(event);
1395             return true;
1396             break;
[509]1397
[472]1398           case EVENT_ID_ADD_VARIABLE_GROUP :
[651]1399             recvAddVariableGroup(event);
1400             return true;
1401             break;
[300]1402           default :
[651]1403              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1404           return false;
[300]1405        }
1406      }
1407   }
[1622]1408   CATCH
[509]1409
[1622]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   }
[509]1430
[219]1431   ///---------------------------------------------------------------
1432
[335]1433} // namespace xios
Note: See TracBrowser for help on using the repository browser.