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

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

Xios coupling
some cleaning...
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: 43.8 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
[1009]242      set<StdString> setAxis;
243      set<StdString> setDomains;
[379]244
245      std::vector<CField*>::iterator it, end = this->enabledFields.end();
[609]246      for (it = this->enabledFields.begin(); it != end; it++)
[379]247      {
[1232]248         CField* field = *it;         
[1869]249         std::vector<CAxis*> vecAxis = field->getGrid()->getAxis();
[609]250         for (size_t i = 0; i < vecAxis.size(); ++i)
[1009]251           setAxis.insert(vecAxis[i]->getAxisOutputName());
[1869]252         std::vector<CDomain*> vecDomains = field->getGrid()->getDomains();
[609]253         for (size_t i = 0; i < vecDomains.size(); ++i)
[1009]254           setDomains.insert(vecDomains[i]->getDomainOutputName());
[379]255      }
[609]256      nbAxis = setAxis.size();
257      nbDomains = setDomains.size();
[379]258
[509]259      // create sub communicator for file
[1232]260      createSubComFile();
[692]261
[802]262      if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
[321]263    }
[1622]264    CATCH_DUMP_ATTR
[509]265
[1232]266    //! Initialize a file in order to write into it
267    void CFile::initRead(void)
[1622]268    TRY
[1232]269    {
[1872]270      CContext* context = CContext::getCurrent();
[1232]271      if (checkRead) return;
[1872]272      //createSubComFile();
273      allZoneEmpty = false; 
274      MPI_Comm_dup(context->intraComm_, &fileComm) ;
[1232]275      checkRead = true;
276    }
[1622]277    CATCH_DUMP_ATTR
[1232]278
279    /*!
280      Create a sub communicator in which processes participate in reading/opening file
281    */
282    void CFile::createSubComFile()
[1622]283    TRY
[1232]284    {
285      CContext* context = CContext::getCurrent();
286
287      // create sub communicator for file
288      allZoneEmpty = true;     
289      std::vector<CField*>::iterator it, end = this->enabledFields.end();
290      for (it = this->enabledFields.begin(); it != end; it++)
291      {
292         CField* field = *it;
[1869]293         bool nullGrid = (nullptr == field->getGrid());
294         allZoneEmpty &= nullGrid ? false : !field->getGrid()->doGridHaveDataToWrite();
[1232]295      }
296
297      int color = allZoneEmpty ? 0 : 1;
[1853]298      MPI_Comm_split(context->intraComm_, color, context->intraCommRank_, &fileComm);
[1639]299      if (allZoneEmpty) MPI_Comm_free(&fileComm);
[1232]300    }
[1622]301    CATCH_DUMP_ATTR
[1232]302
[1136]303    /*
304       Check condition to write into a file
305       For now, we only use the level-2 server to write files (if this mode is activated)
306       or classical server to do this job.
307    */
308    void CFile::checkWriteFile(void)
[1622]309    TRY
[321]310    {
[1054]311      CContext* context = CContext::getCurrent();
[1961]312
313      if (mode.isEmpty() || mode.getValue() == mode_attr::write)
314      {
315        CTimer::get("Files : create headers").resume();
316        if (!isOpen) createHeader();
317        CTimer::get("Files : create headers").suspend();
318        checkSync();
319      }       
320      checkSplit(); 
[1136]321    }
[1622]322    CATCH_DUMP_ATTR
[1136]323
324    /*
325       Check condition to read from a file
326       For now, we only use the level-1 server to write files (if this mode is activated)
327       or classical server to do this job.
328       This function can be used by client for reading metadata
329    */
330    void CFile::checkReadFile(void)
[1622]331    TRY
[1136]332    {
333      CContext* context = CContext::getCurrent();
334      // Done by classical server or secondary server
335      // TODO: This condition should be changed soon. It only works with maximum number of level as 2
[1761]336
[1871]337//ym      if (CServer::serverLevel == 0 || CServer::serverLevel == 1)
338// ym client must doing it also
339//      if (context->getServiceType()==CServicesManager::IO_SERVER || context->getServiceType()==CServicesManager::GATHERER)
340//      {
[1136]341        if (!mode.isEmpty() && mode.getValue() == mode_attr::read)
[1054]342        {
[1158]343          CTimer::get("Files : open headers").resume();
[1232]344         
345          if (!isOpen) openInReadMode();
346
[1158]347          CTimer::get("Files : open headers").suspend();
[1054]348        }
[1136]349        //checkSplit(); // Really need for reading?
[1871]350 //     }
[321]351    }
[1622]352    CATCH_DUMP_ATTR
[509]353
354    /*!
[1232]355      Verify if a process participates in an opening-file communicator
356      \return true if the process doesn't participate in opening file
357    */
358    bool CFile::isEmptyZone()
[1622]359    TRY
[1232]360    {
361      return allZoneEmpty;
362    }
[1622]363    CATCH_DUMP_ATTR
[1232]364
365    /*!
[509]366    \brief Verify if synchronisation should be done
367        If syn option is enabled, syn frequence and current time will be used to
368    calculate the moment to syn file(s)
369    \return True if it is the moment to synchronize file, otherwise false
370    */
[321]371   bool CFile::checkSync(void)
[1622]372   TRY
[321]373   {
[651]374     CContext* context = CContext::getCurrent();
375     const CDate& currentDate = context->calendar->getCurrentDate();
[538]376     if (!sync_freq.isEmpty())
[321]377     {
[651]378       if (lastSync + sync_freq.getValue() <= currentDate)
[321]379       {
[651]380         lastSync = currentDate;
381         data_out->syncFile();
382         return true;
[321]383        }
384      }
[651]385      return false;
[321]386    }
[1622]387   CATCH_DUMP_ATTR
[509]388
389    /*!
390    \brief Verify if splitting should be done
391        If split option is enabled, split frequence and current time will be used to
392    calculate the moment to split file
393    \return True if it is the moment to split file, otherwise false
394    */
[321]395    bool CFile::checkSplit(void)
[1622]396    TRY
[321]397    {
[651]398      CContext* context = CContext::getCurrent();
399      const CDate& currentDate = context->calendar->getCurrentDate();
[538]400      if (!split_freq.isEmpty())
[321]401      {
[651]402        if (currentDate > lastSplit + split_freq.getValue())
[321]403        {
[651]404          lastSplit = lastSplit + split_freq.getValue();
[347]405          std::vector<CField*>::iterator it, end = this->enabledFields.end();
[1961]406/*          for (it = this->enabledFields.begin(); it != end; it++)
[599]407          {
408            (*it)->resetNStep();
409            (*it)->resetNStepMax();
[1961]410          }*/
[599]411          if (mode.isEmpty() || mode.getValue() == mode_attr::write)
[651]412            createHeader();
[599]413          else
414            openInReadMode();
[651]415          return true;
[321]416        }
417      }
[651]418      return false;
[321]419    }
[1622]420    CATCH_DUMP_ATTR
[509]421
[1961]422
[509]423   /*!
424   \brief Create header of netcdf file
425   There are some information to fill in header of each netcdf.
426   */
[300]427   void CFile::createHeader(void)
[1622]428   TRY
[219]429   {
[651]430      CContext* context = CContext::getCurrent();
[1853]431     
[1232]432      if (!allZoneEmpty)
[219]433      {
[773]434         StdString filename = getFileOutputName();
[875]435
436// determine splitting format in the file name  : firstPart%start_date%middlePart%end_date%lastPart
437
438         std::string strStartDate="%start_date%" ;
439         std::string strEndDate="%end_date%" ;
440
441         std::string firstPart ;
442         std::string middlePart ;
443         std::string lastPart ;
444         size_t pos1, pos2 ;
445         bool hasStartDate=false ;
[920]446         bool hasEndDate=false ;
447         bool hasSplit = (!split_freq.isEmpty());
[875]448                 
449         pos1=filename.find(strStartDate) ;
450         if (pos1!=std::string::npos)
451         {
452           firstPart=filename.substr(0,pos1) ;
453           pos1+=strStartDate.size() ;
454           hasStartDate=true ;
455         }
456         else pos1=0 ;
457
458         pos2=filename.find(strEndDate,pos1) ;
459         if (pos2!=std::string::npos)
460         {
461           middlePart=filename.substr(pos1,pos2-pos1) ;
462           pos2+=strEndDate.size() ;
463           lastPart=filename.substr(pos2,filename.size()-pos2) ;
464           hasEndDate=true ;
465         }
466         else middlePart=filename.substr(pos1,filename.size()) ;
467
468         if (!hasStartDate && !hasEndDate)
469         {
470           hasStartDate=true ;
471           hasEndDate=true;
472           firstPart=middlePart ;
[920]473           if (hasSplit) firstPart +="_";
[875]474           middlePart="-" ;
475         }
[920]476   
[300]477         StdOStringStream oss;
[538]478
[431]479         if (!split_freq.isEmpty())
480         {
[1201]481           CDate split_start ;
482           CDate splitEnd ;
483           if (!split_start_offset.isEmpty()) split_start=lastSplit + split_start_offset ;
484           else split_start=lastSplit ;
[702]485
[1201]486           splitEnd = lastSplit + split_freq ;
487           if (!split_last_date.isEmpty())
488           {
489             CDate splitLastDate=CDate::FromString(split_last_date,*CContext::getCurrent()->getCalendar()) ;
490             if( splitLastDate < splitEnd)  splitEnd=splitLastDate ;
491           }
492           
493           if (!split_end_offset.isEmpty()) splitEnd = splitEnd + split_end_offset;
494           else splitEnd = splitEnd - 1 * Second;
495
[651]496           string splitFormat;
[431]497           if (split_freq_format.isEmpty())
498           {
[1516]499             CDuration splitFreq = split_freq.getValue();
500             splitFreq.solveTimeStep(*CContext::getCurrent()->getCalendar());
501             if (splitFreq.second != 0) splitFormat = "%y%mo%d%h%mi%s";
502             else if (splitFreq.minute != 0) splitFormat = "%y%mo%d%h%mi";
503             else if (splitFreq.hour != 0) splitFormat = "%y%mo%d%h";
504             else if (splitFreq.day != 0) splitFormat = "%y%mo%d";
505             else if (splitFreq.month != 0) splitFormat = "%y%mo";
[538]506             else splitFormat = "%y";
[431]507           }
[651]508           else splitFormat = split_freq_format;
[702]509
[875]510           oss << firstPart ;
[1201]511           if (hasStartDate) oss << split_start.getStr(splitFormat) ;
[875]512           oss << middlePart ;
513           if (hasEndDate) oss << splitEnd.getStr(splitFormat);
514           oss << lastPart ;
[702]515
[1316]516           StdString keySuffix("CFile::"+getFileOutputName()+"::") ; 
[1158]517           context->registryOut->setKey(keySuffix+"splitStart", lastSplit);
518           context->registryOut->setKey(keySuffix+"splitEnd",   splitEnd);
[431]519         }
[875]520         else oss<<firstPart<<lastPart ;
[509]521
[528]522        bool append = !this->append.isEmpty() && this->append.getValue();
[567]523
[517]524         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
[878]525         bool useCFConvention = convention.isEmpty() || convention == convention_attr::CF;
[517]526
[651]527         bool multifile = true;
[300]528         if (!type.isEmpty())
529         {
[651]530           if (type == type_attr::one_file) multifile = false;
531           else if (type == type_attr::multiple_file) multifile = true;
[379]532
[509]533         }
[379]534#ifndef USING_NETCDF_PAR
535         if (!multifile)
536         {
[651]537            info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
538            multifile = true;
[379]539          }
540#endif
[509]541         if (multifile)
[300]542         {
[651]543            int commSize, commRank;
[1639]544            MPI_Comm_size(fileComm, &commSize);
545            MPI_Comm_rank(fileComm, &commRank);
[509]546
[1853]547            if (context->intraCommSize_ > 1)
[375]548            {
[651]549              oss << "_" ;
550              int width=0; int n = commSize-1;
551              while (n != 0) { n = n / 10; width++;}
[509]552              if (!min_digits.isEmpty())
[651]553                if (width < min_digits) width = min_digits;
554              oss.width(width);
555              oss.fill('0');
556              oss << right << commRank;
[375]557            }
[300]558         }
559         oss << ".nc";
560
[526]561         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
562
563         if (isOpen) data_out->closeFile();
564
[1542]565        data_out = std::shared_ptr<CDataOutput>(new CNc4DataOutput(this, oss.str(), append, useClassicFormat, useCFConvention,
[802]566                                                              fileComm, multifile, isCollective, time_counter_name));
[528]567        isOpen = true;
[300]568
[528]569        data_out->writeFile(CFile::get(this));
570
[1494]571        if (!useCFConvention) sortEnabledFieldsForUgrid();
572
[528]573        // Do not recreate the file structure if opening an existing file
574        if (!data_out->IsInAppendMode())
575        {
576          std::vector<CField*>::iterator it, end = this->enabledFields.end();
577          for (it = this->enabledFields.begin(); it != end; it++)
578          {
[347]579            CField* field = *it;
[300]580            this->data_out->writeFieldGrid(field);
[528]581          }
582          this->data_out->writeTimeDimension();
[509]583
[528]584          for (it = this->enabledFields.begin(); it != end; it++)
585          {
[347]586            CField* field = *it;
[1158]587            this->data_out->writeFieldTimeAxis(field);
588          }
589         
590          for (it = this->enabledFields.begin(); it != end; it++)
591          {
592            CField* field = *it;
[300]593            this->data_out->writeField(field);
[528]594          }
[509]595
[651]596          vector<CVariable*> listVars = getAllVariables();
[528]597          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
598            this->data_out->writeAttribute(*it);
[509]599
[528]600          this->data_out->definition_end();
601        }
[1158]602        else
603        {
604          // check time axis even in append mode
605          std::vector<CField*>::iterator it, end = this->enabledFields.end();
606          for (it = this->enabledFields.begin(); it != end; it++)
607          {
608            CField* field = *it;
609            this->data_out->writeFieldTimeAxis(field);
610          }
611        }
[219]612      }
613   }
[1622]614   CATCH_DUMP_ATTR
[219]615
[599]616  /*!
617  \brief Open an existing NetCDF file in read-only mode
618  */
[1232]619  void CFile::openInReadMode()
[1622]620  TRY
[599]621  {
622    CContext* context = CContext::getCurrent();
[1639]623    MPI_Comm readComm = this->fileComm;
[599]624
[1232]625    if (!allZoneEmpty)
[599]626    {
[773]627      StdString filename = getFileOutputName();
[599]628      StdOStringStream oss;
629      oss << filename;
630
631      if (!split_freq.isEmpty())
632      {
633        string splitFormat;
634        if (split_freq_format.isEmpty())
635        {
[1516]636          CDuration splitFreq = split_freq.getValue();
637          splitFreq.solveTimeStep(*CContext::getCurrent()->getCalendar());
638          if (splitFreq.second != 0) splitFormat = "%y%mo%d%h%mi%s";
639          else if (splitFreq.minute != 0) splitFormat = "%y%mo%d%h%mi";
640          else if (splitFreq.hour != 0) splitFormat = "%y%mo%d%h";
641          else if (splitFreq.day != 0) splitFormat = "%y%mo%d";
642          else if (splitFreq.month != 0) splitFormat = "%y%mo";
[599]643          else splitFormat = "%y";
644        }
[651]645        else splitFormat = split_freq_format;
646        oss << "_" << lastSplit.getStr(splitFormat)
647        << "-" << (lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
[599]648      }
649
650      bool multifile = true;
651      if (!type.isEmpty())
652      {
653        if (type == type_attr::one_file) multifile = false;
654        else if (type == type_attr::multiple_file) multifile = true;
655      }
656  #ifndef USING_NETCDF_PAR
657      if (!multifile)
658      {
659        info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
660        multifile = true;
661      }
662  #endif
663      if (multifile)
664      {
665        int commSize, commRank;
[1639]666        MPI_Comm_size(readComm, &commSize);
667        MPI_Comm_rank(readComm, &commRank);
[599]668
[1853]669        if (context->intraCommSize_ > 1)
[599]670        {
[651]671          oss << "_";
[599]672          int width = 0, n = commSize - 1;
673          while (n != 0) { n = n / 10; width++; }
674          if (!min_digits.isEmpty() && width < min_digits)
675            width = min_digits;
676          oss.width(width);
677          oss.fill('0');
678          oss << right << commRank;
679        }
680      }
681      oss << ".nc";
682
683      bool isCollective = par_access.isEmpty() || par_access == par_access_attr::collective;
[1485]684      bool readMetaDataPar = true;
[1853]685      if (context->getServiceType()==CServicesManager::CLIENT) readMetaDataPar = (read_metadata_par.isEmpty()) ? false : read_metadata_par;
[599]686
687      if (isOpen) data_out->closeFile();
[1486]688      bool ugridConvention = !convention.isEmpty() ? (convention == convention_attr::UGRID) : false;
689      if (time_counter_name.isEmpty())
[1542]690        data_in = std::shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective, readMetaDataPar, ugridConvention));
[1486]691      else
[1542]692        data_in = std::shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), readComm, multifile, isCollective, readMetaDataPar, ugridConvention, time_counter_name));
[599]693      isOpen = true;
694    }
695  }
[1622]696  CATCH_DUMP_ATTR
[599]697
[509]698   //! Close file
[286]699   void CFile::close(void)
[1622]700   TRY
[286]701   {
[1232]702     if (!allZoneEmpty)
[509]703       if (isOpen)
[321]704       {
[599]705         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
706          this->data_out->closeFile();
707         else
708          this->data_in->closeFile();
[1232]709        isOpen = false;
[321]710       }
[1639]711      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
[286]712   }
[1622]713   CATCH_DUMP_ATTR
714
[219]715   //----------------------------------------------------------------
716
[775]717   void CFile::readAttributesOfEnabledFieldsInReadMode()
[1622]718   TRY
[775]719   {
720     if (enabledFields.empty()) return;
721
722     // Just check file and try to open it
[805]723     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
724
[1136]725     checkReadFile();
[805]726
[775]727     for (int idx = 0; idx < enabledFields.size(); ++idx)
728     {
729        // First of all, find out which domain and axis associated with this field
730        enabledFields[idx]->solveGridReference();
731
732        // Read attributes of domain and axis from this file
733        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
734
735        // Now complete domain and axis associated with this field
736        enabledFields[idx]->solveGenerateGrid();
737
738        // Read necessary value from file
739        this->data_in->readFieldAttributesValues(enabledFields[idx]);
740
741        // Fill attributes for base reference
742        enabledFields[idx]->solveGridDomainAxisBaseRef();
743     }
744
745     // Now everything is ok, close it
746     close();
747   }
[1622]748   CATCH_DUMP_ATTR
[775]749
[1871]750   void CFile::readFieldAttributesMetaData(CField* field)
751   {
752     this->data_in->readFieldAttributesMetaData(field);
753   }
754
755   void CFile::readFieldAttributesValues(CField* field)
756   {
757     this->data_in->readFieldAttributesValues(field);
758   }
[509]759   /*!
760   \brief Parse xml file and write information into file object
761   \param [in] node xmld node corresponding in xml file
762   */
[219]763   void CFile::parse(xml::CXMLNode & node)
[1622]764   TRY
[219]765   {
766      SuperClass::parse(node);
[509]767
[472]768      if (node.goToChildElement())
769      {
770        do
771        {
772           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
773           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
[651]774        } while (node.goToNextElement());
[472]775        node.goToParentElement();
[219]776      }
[1622]777   }
778   CATCH_DUMP_ATTR
[472]779
[219]780   //----------------------------------------------------------------
781
[509]782   /*!
783   \brief Represent a file in form of string with all its info
784   \return String
785   */
[219]786   StdString CFile::toString(void) const
[1622]787   TRY
[219]788   {
789      StdOStringStream oss;
790
791      oss << "<" << CFile::GetName() << " ";
792      if (this->hasId())
793         oss << " id=\"" << this->getId() << "\" ";
794      oss << SuperClassAttribute::toString() << ">" << std::endl;
[347]795      if (this->getVirtualFieldGroup() != NULL)
[219]796         oss << *this->getVirtualFieldGroup() << std::endl;
797      oss << "</" << CFile::GetName() << " >";
798      return (oss.str());
799   }
[1622]800   CATCH
[219]801
802   //----------------------------------------------------------------
[509]803
804   /*!
805   \brief Find all inheritace among objects in a file.
806   \param [in] apply (true) write attributes of parent into ones of child if they are empty
807                     (false) write attributes of parent into a new container of child
808   \param [in] parent
809   */
[445]810   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
[1622]811   TRY
[219]812   {
[445]813      SuperClassAttribute::setAttributes(parent,apply);
[509]814      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
[472]815      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
[219]816   }
[1622]817   CATCH_DUMP_ATTR
[219]818
819   //----------------------------------------------------------------
820
[509]821   /*!
822   \brief Resolve all reference of active fields.
823      In order to know exactly which data each active field has, a search for all its
824   reference to find its parents or/and its base reference object must be done. Moreover
825   during this search, there are some information that can only be sent to server AFTER
826   all information of active fields are created on server side, e.g: checking mask or index
827   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
828   */
[1784]829   void CFile::solveOnlyRefOfEnabledFields(void)
[1622]830   TRY
[823]831   {
832     int size = this->enabledFields.size();
833     for (int i = 0; i < size; ++i)
834     {
[1784]835       this->enabledFields[i]->solveOnlyReferenceEnabledField();
[823]836     }
837   }
[1622]838   CATCH_DUMP_ATTR
[823]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;
872
873     for (int i = 0; i < size; ++i)
874     {
875       std::vector<CDomain*> domain = this->enabledFields[i]->getRelGrid()->getDomains();
876       if (domain.size() != 1)
877       {
878         ERROR("void CFile::sortEnabledFieldsForUgrid()",
879               "A domain, and only one, should be defined for grid "<< this->enabledFields[i]->getRelGrid()->getId() << ".");
880       }
881       StdString domainName = domain[0]->getDomainOutputName();
882       int nvertex;
883       if (domain[0]->nvertex.isEmpty())
884       {
885         ERROR("void CFile::sortEnabledFieldsForUgrid()",
886               "Attributes nvertex must be defined for domain "<< domain[0]->getDomainOutputName() << ".");
887       }
888       else
889         nvertex = domain[0]->nvertex;
890
891       for (int j = 0; j < i; ++j)
892       {
893         if (domainName == domainNames[j] && nvertex > domainNvertices[j])
894         {
895           CField* tmpSwap = this->enabledFields[j];
896           this->enabledFields[j] = this->enabledFields[i];
897           this->enabledFields[i] = tmpSwap;
898           domainNames.push_back(domainNames[j]);
899           domainNames[j] = domainName;
900           domainNvertices.push_back(domainNvertices[j]);
901           domainNvertices[j] = nvertex;
902         }
903         else
904         {
905           domainNames.push_back(domainName);
906           domainNvertices.push_back(nvertex);
907         }
908       }
909       if (i==0)
910       {
911         domainNames.push_back(domainName);
912         domainNvertices.push_back(nvertex);
913       }
914     }
915   }
[1622]916   CATCH_DUMP_ATTR
[1494]917
[1025]918   void CFile::sendGridOfEnabledFields()
[1622]919   TRY
[1025]920   { 
921     int size = this->enabledFields.size();
922     for (int i = 0; i < size; ++i)
923     {
924       this->enabledFields[i]->sendGridOfEnabledFields();
925     }
926   }
[1622]927   CATCH_DUMP_ATTR
[1025]928
[823]929   void CFile::generateNewTransformationGridDest()
[1622]930   TRY
[823]931   {
932     int size = this->enabledFields.size();
933     for (int i = 0; i < size; ++i)
934     {
935       this->enabledFields[i]->generateNewTransformationGridDest();
936     }
937   }
[1622]938   CATCH_DUMP_ATTR
[823]939
940   /*!
941   \brief Resolve all reference of active fields.
942      In order to know exactly which data each active field has, a search for all its
943   reference to find its parents or/and its base reference object must be done. Moreover
944   during this search, there are some information that can only be sent to server AFTER
945   all information of active fields are created on server side, e.g: checking mask or index
946   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
947   */
[1784]948   void CFile::solveAllRefOfEnabledFieldsAndTransform(void)
[1622]949   TRY
[459]950   {
[509]951     int size = this->enabledFields.size();
952     for (int i = 0; i < size; ++i)
[1144]953     {       
[1129]954      this->enabledFields[i]->solveAllEnabledFieldsAndTransform();
[509]955     }
[459]956   }
[1622]957   CATCH_DUMP_ATTR
[509]958
959   /*!
[640]960    * Constructs the filter graph for each active field.
961    *
962    * \param gc the garbage collector to use when building the filter graph
963    */
964   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
[1622]965   TRY
[640]966   {
967     int size = this->enabledFields.size();
968     for (int i = 0; i < size; ++i)
969     {
970       this->enabledFields[i]->buildFilterGraph(gc, true);
971     }
972   }
[1622]973   CATCH_DUMP_ATTR
[640]974
975   /*!
[1358]976    * Post-process the filter graph for each active field.
977    */
978   void CFile::postProcessFilterGraph()
[1622]979   TRY
[1358]980   {
981     int size = this->enabledFields.size();
982     for (int i = 0; i < size; ++i)
983     {
984       this->enabledFields[i]->checkIfMustAutoTrigger();
985     }
986   }
[1622]987   CATCH_DUMP_ATTR
[1358]988
989   /*!
[598]990     Prefetching the data for enabled fields read from file.
991   */
992   void CFile::prefetchEnabledReadModeFields(void)
[1622]993   TRY
[598]994   {
995     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
996       return;
997
998     int size = this->enabledFields.size();
999     for (int i = 0; i < size; ++i)
[1934]1000       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
[598]1001   }
[1622]1002   CATCH_DUMP_ATTR
[598]1003
1004   /*!
[1358]1005     Do all pre timestep operations for enabled fields in read mode:
1006      - Check that the data excepted from server has been received
1007      - Check if some filters must auto-trigger
1008   */
1009   void CFile::doPreTimestepOperationsForEnabledReadModeFields(void)
[1622]1010   TRY
[1358]1011   {
1012     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
1013       return;
1014
1015     int size = this->enabledFields.size();
1016     for (int i = 0; i < size; ++i)
1017     {
1018       this->enabledFields[i]->checkForLateDataFromServer();
1019       this->enabledFields[i]->autoTriggerIfNeeded();
1020     }
1021   }
[1622]1022   CATCH_DUMP_ATTR
[1358]1023
1024   /*!
[1318]1025     Do all post timestep operations for enabled fields in read mode:
1026      - Prefetch the data read from file when needed
[598]1027   */
[1318]1028   void CFile::doPostTimestepOperationsForEnabledReadModeFields(void)
[1622]1029   TRY
[598]1030   {
1031     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
1032       return;
1033
1034     int size = this->enabledFields.size();
1035     for (int i = 0; i < size; ++i)
[1318]1036     {
[598]1037       this->enabledFields[i]->sendReadDataRequestIfNeeded();
[1318]1038     }
[598]1039   }
[1622]1040   CATCH_DUMP_ATTR
[598]1041
[445]1042   void CFile::solveFieldRefInheritance(bool apply)
[1622]1043   TRY
[219]1044   {
[878]1045      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
[347]1046      std::vector<CField*> allF = this->getAllFields();
[219]1047      for (unsigned int i = 0; i < allF.size(); i++)
[445]1048         allF[i]->solveRefInheritance(apply);
[219]1049   }
[1622]1050   CATCH_DUMP_ATTR
[219]1051
1052   //----------------------------------------------------------------
1053
[509]1054   /*!
1055   \brief Add a field into file.
1056      A field is added into file and it will be written out if the file is enabled and
1057   level of this field is smaller than level_output. A new field won't be created if one
1058   with id has already existed
1059   \param [in] id String identity of new field
1060   \return Pointer to added (or already existed) field
1061   */
[347]1062   CField* CFile::addField(const string& id)
[1622]1063   TRY
[300]1064   {
[651]1065     return vFieldGroup->createChild(id);
[300]1066   }
[1622]1067   CATCH_DUMP_ATTR
[219]1068
[509]1069   /*!
1070   \brief Add a field group into file.
1071      A field group is added into file and it will play a role as parents for fields.
1072   A new field group won't be created if one with id has already existed
1073   \param [in] id String identity of new field group
1074   \return Pointer to added (or already existed) field group
1075   */
[347]1076   CFieldGroup* CFile::addFieldGroup(const string& id)
[1622]1077   TRY
[300]1078   {
[651]1079     return vFieldGroup->createChildGroup(id);
[300]1080   }
[1622]1081   CATCH_DUMP_ATTR
[509]1082
1083   /*!
1084   \brief Add a variable into file.
1085      A variable is added into file and if one with id has already existed, pointer to
1086   it will be returned.
1087      Variable as long as attributes are information container of file.
1088   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
1089   to fill in (extra) information for a file.
1090   \param [in] id String identity of new variable
1091   \return Pointer to added (or already existed) variable
1092   */
[472]1093   CVariable* CFile::addVariable(const string& id)
[1622]1094   TRY
[472]1095   {
[651]1096     return vVariableGroup->createChild(id);
[472]1097   }
[1622]1098   CATCH_DUMP_ATTR
[472]1099
[509]1100   /*!
1101   \brief Add a variable group into file.
1102      A variable group is added into file and it will play a role as parents for variables.
1103   A new variable group won't be created if one with id has already existed
1104   \param [in] id String identity of new variable group
1105   \return Pointer to added (or already existed) variable group
1106   */
[472]1107   CVariableGroup* CFile::addVariableGroup(const string& id)
[1622]1108   TRY
[472]1109   {
[651]1110     return vVariableGroup->createChildGroup(id);
[472]1111   }
[1622]1112   CATCH_DUMP_ATTR
[509]1113
[1021]1114   void CFile::setContextClient(CContextClient* newContextClient)
[1622]1115   TRY
[1021]1116   {
1117     client = newContextClient;
[1294]1118     size_t size = this->enabledFields.size();
1119     for (size_t i = 0; i < size; ++i)
1120     {
1121       this->enabledFields[i]->setContextClient(newContextClient);
1122     }
[1021]1123   }
[1622]1124   CATCH_DUMP_ATTR
[1021]1125
1126   CContextClient* CFile::getContextClient()
[1622]1127   TRY
[1021]1128   {
1129     return client;
1130   }
[1622]1131   CATCH_DUMP_ATTR
[1021]1132
[1232]1133   void CFile::setReadContextClient(CContextClient* readContextclient)
[1622]1134   TRY
[1232]1135   {
1136     read_client = readContextclient;
1137   }
[1622]1138   CATCH_DUMP_ATTR
[1232]1139
1140   CContextClient* CFile::getReadContextClient()
[1622]1141   TRY
[1232]1142   {
1143     return read_client;
1144   }
[1622]1145   CATCH_DUMP_ATTR
[1232]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.