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

Last change on this file since 2150 was 2150, checked in by jderouillat, 3 years ago

Fix typo in : Do not remove ranks with empty data from file writing communicators

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