source: XIOS3/branches/xios-3.0-beta/src/node/file.cpp @ 2521

Last change on this file since 2521 was 2417, checked in by jderouillat, 21 months ago

Backport commits [1977, 2181, 2200-2202, 2250, 2252] related to UGRID in XIOS3 beta

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