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

Last change on this file was 2628, checked in by jderouillat, 3 months ago

New timers integration/reporting

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