source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/file.cpp @ 1872

Last change on this file since 1872 was 1872, checked in by ymipsl, 4 years ago

Some update on XIOS_COUPLING branch...

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