source: XIOS/trunk/src/node/file.cpp @ 599

Last change on this file since 599 was 599, checked in by rlacroix, 9 years ago

Implement reading fields from NetCDF files.

  • 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: 32.8 KB
Line 
1#include "file.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "object_factory.hpp"
7#include "context.hpp"
8#include "context_server.hpp"
9#include "nc4_data_output.hpp"
10#include "nc4_data_input.hpp"
11#include "calendar_util.hpp"
12#include "date.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "context_client.hpp"
17#include "mpi.hpp"
18
19namespace xios {
20
21   /// ////////////////////// Définitions ////////////////////// ///
22
23   CFile::CFile(void)
24      : CObjectTemplate<CFile>(), CFileAttributes()
25      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
26   {
27     setVirtualFieldGroup() ;
28     setVirtualVariableGroup() ;
29   }
30
31   CFile::CFile(const StdString & id)
32      : CObjectTemplate<CFile>(id), CFileAttributes()
33      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
34    {
35      setVirtualFieldGroup() ;
36      setVirtualVariableGroup() ;
37    }
38
39   CFile::~CFile(void)
40   { /* Ne rien faire de plus */ }
41
42   ///---------------------------------------------------------------
43  //! Get name of file
44   StdString CFile::GetName(void)   { return (StdString("file")); }
45   StdString CFile::GetDefName(void){ return (CFile::GetName()); }
46   ENodeType CFile::GetType(void)   { return (eFile); }
47
48   //----------------------------------------------------------------
49   /*!
50   \brief Get data writer object.
51   Each enabled file in xml represents a physical netcdf file.
52   This function allows to access the data writer object.
53   \return data writer object.
54   */
55   boost::shared_ptr<CDataOutput> CFile::getDataOutput(void) const
56   {
57      return data_out;
58   }
59
60   /*!
61   \brief Get data reader object.
62   Each enabled file in xml represents a physical netcdf file.
63   This function allows to access the data reader object.
64   \return data reader object.
65   */
66   boost::shared_ptr<CDataInput> CFile::getDataInput(void) const
67   {
68      return data_in;
69   }
70
71   /*!
72   \brief Get virtual field group
73      In each file, there always exists a field group which is the ancestor of all
74   fields in the file. This is considered be virtual because it is created automatically during
75   file initialization and it normally doesn't appear on xml file
76   \return Pointer to field group
77   */
78   CFieldGroup* CFile::getVirtualFieldGroup(void) const
79   {
80      return (this->vFieldGroup);
81   }
82
83   /*!
84   \brief Get virtual variable group
85      In each file, there always exists a variable group which is the ancestor of all
86   variable in the file. This is considered be virtual because it is created automatically during
87   file initialization and it normally doesn't appear on xml file
88   \return Pointer to variable group
89   */
90   CVariableGroup* CFile::getVirtualVariableGroup(void) const
91   {
92      return (this->vVariableGroup);
93   }
94
95   //! Get all fields of a file
96   std::vector<CField*> CFile::getAllFields(void) const
97   {
98      return (this->vFieldGroup->getAllChildren());
99   }
100
101   //! Get all variables of a file
102   std::vector<CVariable*> CFile::getAllVariables(void) const
103   {
104      return (this->vVariableGroup->getAllChildren());
105   }
106
107   //----------------------------------------------------------------
108   /*!
109   \brief Get all enabled fields of file
110      A field is considered to be enabled if it fullfil these conditions: it is enabled, inside a enabled file
111   and its own level is not larger than file output level.
112   \param [in] default_outputlevel default value output level of file
113   \param [in] default_level default value level of field
114   \param [in] default_enabled flag determine by default if field is enabled
115   \return Vector of pointers of enabled fields
116   */
117   std::vector<CField*> CFile::getEnabledFields(int default_outputlevel,
118                                                int default_level,
119                                                bool default_enabled)
120   {
121      if (!this->enabledFields.empty())
122         return (this->enabledFields);
123
124      const int _outputlevel =
125         (!output_level.isEmpty()) ? output_level.getValue() : default_outputlevel;
126      std::vector<CField*>::iterator it;
127      this->enabledFields = this->getAllFields();
128
129      std::vector<CField*> newEnabledFields;
130
131      for ( it = this->enabledFields.begin() ; it != this->enabledFields.end(); it++ )
132      {
133         if (!(*it)->enabled.isEmpty()) // Si l'attribut 'enabled' est défini ...
134         {
135            if (! (*it)->enabled.getValue()) continue;
136//            { it--; this->enabledFields.erase(it+1); continue; }
137         }
138         else // Si l'attribut 'enabled' n'est pas défini ...
139         {
140            if (!default_enabled) continue ;
141//            { it--; this->enabledFields.erase(it+1); continue; }
142         }
143
144         if (!(*it)->level.isEmpty()) // Si l'attribut 'level' est défini ...
145         {
146            if ((*it)->level.getValue() > _outputlevel) continue ;
147//            { it--; this->enabledFields.erase(it+1); continue; }
148         }
149         else // Si l'attribut 'level' n'est pas défini ...
150         {
151            if (default_level > _outputlevel) continue ;
152//            { it--; this->enabledFields.erase(it+1); continue; }
153         }
154
155//         CField* field_tmp=(*it).get() ;
156//         shared_ptr<CField> sptfield=*it ;
157//         field_tmp->refObject.push_back(sptfield) ;
158         newEnabledFields.push_back(*it) ;
159         // Le champ est finalement actif, on y ajoute sa propre reference.
160//         (*it)->refObject.push_back(*it);
161         // Le champ est finalement actif, on y ajoute la référence au champ de base.
162         (*it)->setRelFile(CFile::get(this));
163//         (*it)->baseRefObject->refObject.push_back(*it);
164         // A faire, ajouter les references intermediaires...
165      }
166      enabledFields=newEnabledFields ;
167
168      return (this->enabledFields);
169   }
170
171   //----------------------------------------------------------------
172   //! Change virtual field group to a new one
173   void CFile::setVirtualFieldGroup(CFieldGroup* newVFieldGroup)
174   {
175      this->vFieldGroup = newVFieldGroup;
176   }
177
178   //! Change virtual variable group to new one
179   void CFile::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
180   {
181      this->vVariableGroup = newVVariableGroup;
182   }
183
184   //----------------------------------------------------------------
185   //! Create virtual field group, which is done normally on initializing file
186   void CFile::setVirtualFieldGroup(void)
187   {
188      this->setVirtualFieldGroup(CFieldGroup::create());
189   }
190
191   //! Create virtual variable group, which is done normally on initializing file
192   void CFile::setVirtualVariableGroup(void)
193   {
194      this->setVirtualVariableGroup(CVariableGroup::create());
195   }
196
197   //----------------------------------------------------------------
198   bool CFile::isSyncTime(void)
199   {
200     CContext* context = CContext::getCurrent() ;
201     const CDate& currentDate = context->calendar->getCurrentDate() ;
202     if (!sync_freq.isEmpty())
203     {
204       if (*lastSync + sync_freq.getValue() < currentDate)
205       {
206         *lastSync=currentDate ;
207         return true ;
208        }
209      }
210      return false ;
211    }
212
213   //! Initialize a file in order to write into it
214   void CFile::initFile(void)
215   {
216      CContext* context = CContext::getCurrent() ;
217      const CDate& currentDate = context->calendar->getCurrentDate() ;
218      CContextServer* server=context->server ;
219
220      lastSync=new CDate(currentDate) ;
221      lastSplit=new CDate(currentDate) ;
222      isOpen=false ;
223
224      allDomainEmpty=true ;
225
226      set<CDomain*> setDomain ;
227
228      std::vector<CField*>::iterator it, end = this->enabledFields.end();
229      for (it = this->enabledFields.begin() ;it != end; it++)
230      {
231         CField* field = *it;
232//         allDomainEmpty&=field->grid->domain->isEmpty() ;
233         allDomainEmpty&=(!field->grid->doGridHaveDataToWrite());
234         std::vector<CDomain*> vecDomain = field->grid->getDomains();
235         for (int i = 0; i < vecDomain.size(); ++i)
236            setDomain.insert(vecDomain[i]);
237//            setDomain.insert(field->grid->domain) ;
238      }
239      nbDomain=setDomain.size() ;
240
241      // create sub communicator for file
242      int color=allDomainEmpty?0:1 ;
243      MPI_Comm_split(server->intraComm,color,server->intraCommRank,&fileComm) ;
244      if (allDomainEmpty) MPI_Comm_free(&fileComm) ;
245      //
246
247    }
248
249    //! Verify state of a file
250    void CFile::checkFile(void)
251    {
252      if (mode.isEmpty() || mode.getValue() == mode_attr::write)
253      {
254        if (!isOpen) createHeader();
255        checkSync();
256      }
257      else
258      {
259        if (!isOpen) openInReadMode();
260      }
261      checkSplit();
262    }
263
264    /*!
265    \brief Verify if synchronisation should be done
266        If syn option is enabled, syn frequence and current time will be used to
267    calculate the moment to syn file(s)
268    \return True if it is the moment to synchronize file, otherwise false
269    */
270   bool CFile::checkSync(void)
271   {
272     CContext* context = CContext::getCurrent() ;
273     const CDate& currentDate = context->calendar->getCurrentDate() ;
274     if (!sync_freq.isEmpty())
275     {
276       if (*lastSync + sync_freq.getValue() <= currentDate)
277       {
278         *lastSync=currentDate ;
279         data_out->syncFile() ;
280         return true ;
281        }
282      }
283      return false ;
284    }
285
286    /*!
287    \brief Verify if splitting should be done
288        If split option is enabled, split frequence and current time will be used to
289    calculate the moment to split file
290    \return True if it is the moment to split file, otherwise false
291    */
292    bool CFile::checkSplit(void)
293    {
294      CContext* context = CContext::getCurrent() ;
295      const CDate& currentDate = context->calendar->getCurrentDate() ;
296      if (!split_freq.isEmpty())
297      {
298        if (currentDate > *lastSplit + split_freq.getValue())
299        {
300          *lastSplit = *lastSplit + split_freq.getValue();
301          std::vector<CField*>::iterator it, end = this->enabledFields.end();
302          for (it = this->enabledFields.begin(); it != end; it++)
303          {
304            (*it)->resetNStep();
305            (*it)->resetNStepMax();
306          }
307          if (mode.isEmpty() || mode.getValue() == mode_attr::write)
308            createHeader() ;
309          else
310            openInReadMode();
311          return true ;
312        }
313      }
314      return false ;
315    }
316
317   /*!
318   \brief Create header of netcdf file
319   There are some information to fill in header of each netcdf.
320   */
321   void CFile::createHeader(void)
322   {
323      CContext* context = CContext::getCurrent() ;
324      CContextServer* server=context->server ;
325
326      if (!allDomainEmpty)
327      {
328         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
329         StdOStringStream oss;
330         oss << filename;
331         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
332
333         if (!split_freq.isEmpty())
334         {
335           string splitFormat ;
336           if (split_freq_format.isEmpty())
337           {
338             if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
339             else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
340             else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
341             else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
342             else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
343             else splitFormat = "%y";
344           }
345           else splitFormat=split_freq_format ;
346           oss << "_" << lastSplit->getStr(splitFormat)
347               << "-" << (*lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
348         }
349
350        bool append = !this->append.isEmpty() && this->append.getValue();
351
352         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
353
354         bool multifile=true ;
355         if (!type.isEmpty())
356         {
357           if (type==type_attr::one_file) multifile=false ;
358           else if (type==type_attr::multiple_file) multifile=true ;
359
360         }
361#ifndef USING_NETCDF_PAR
362         if (!multifile)
363         {
364            info(0)<<"!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : "<<filename<<" ..."<<endl ;
365            multifile=true ;
366          }
367#endif
368         if (multifile)
369         {
370            int commSize, commRank ;
371            MPI_Comm_size(fileComm,&commSize) ;
372            MPI_Comm_rank(fileComm,&commRank) ;
373
374            if (server->intraCommSize > 1)
375            {
376              oss << "_"  ;
377              int width=0 ; int n=commSize-1 ;
378              while(n != 0) { n=n/10 ; width++ ;}
379              if (!min_digits.isEmpty())
380                if (width<min_digits) width=min_digits ;
381              oss.width(width) ;
382              oss.fill('0') ;
383              oss<<right<< commRank;
384            }
385         }
386         oss << ".nc";
387
388         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
389
390         if (isOpen) data_out->closeFile();
391
392        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), append, useClassicFormat,
393                                                              fileComm, multifile, isCollective));
394        isOpen = true;
395
396        data_out->writeFile(CFile::get(this));
397
398        // Do not recreate the file structure if opening an existing file
399        if (!data_out->IsInAppendMode())
400        {
401          std::vector<CField*>::iterator it, end = this->enabledFields.end();
402          for (it = this->enabledFields.begin(); it != end; it++)
403          {
404            CField* field = *it;
405            this->data_out->writeFieldGrid(field);
406          }
407          this->data_out->writeTimeDimension();
408
409          for (it = this->enabledFields.begin(); it != end; it++)
410          {
411            CField* field = *it;
412            this->data_out->writeField(field);
413          }
414
415          vector<CVariable*> listVars = getAllVariables() ;
416          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
417            this->data_out->writeAttribute(*it);
418
419          this->data_out->definition_end();
420        }
421      }
422   }
423
424  /*!
425  \brief Open an existing NetCDF file in read-only mode
426  */
427  void CFile::openInReadMode(void)
428  {
429    CContext* context = CContext::getCurrent();
430    CContextServer* server=context->server;
431
432    if (!allDomainEmpty)
433    {
434      StdString filename = (!name.isEmpty()) ? name.getValue() : getId();
435      StdOStringStream oss;
436      oss << filename;
437      if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
438
439      if (!split_freq.isEmpty())
440      {
441        string splitFormat;
442        if (split_freq_format.isEmpty())
443        {
444          if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
445          else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
446          else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
447          else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
448          else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
449          else splitFormat = "%y";
450        }
451        else splitFormat=split_freq_format;
452        oss << "_" << lastSplit->getStr(splitFormat)
453        << "-" << (*lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
454      }
455
456      bool multifile = true;
457      if (!type.isEmpty())
458      {
459        if (type == type_attr::one_file) multifile = false;
460        else if (type == type_attr::multiple_file) multifile = true;
461      }
462  #ifndef USING_NETCDF_PAR
463      if (!multifile)
464      {
465        info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
466        multifile = true;
467      }
468  #endif
469      if (multifile)
470      {
471        int commSize, commRank;
472        MPI_Comm_size(fileComm, &commSize);
473        MPI_Comm_rank(fileComm, &commRank);
474
475        if (server->intraCommSize > 1)
476        {
477          oss << "_" ;
478          int width = 0, n = commSize - 1;
479          while (n != 0) { n = n / 10; width++; }
480          if (!min_digits.isEmpty() && width < min_digits)
481            width = min_digits;
482          oss.width(width);
483          oss.fill('0');
484          oss << right << commRank;
485        }
486      }
487      oss << ".nc";
488
489      bool isCollective = par_access.isEmpty() || par_access == par_access_attr::collective;
490
491      if (isOpen) data_out->closeFile();
492
493      data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective));
494      isOpen = true;
495    }
496  }
497
498   //! Close file
499   void CFile::close(void)
500   {
501     delete lastSync ;
502     delete lastSplit ;
503     if (!allDomainEmpty)
504       if (isOpen)
505       {
506         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
507          this->data_out->closeFile();
508         else
509          this->data_in->closeFile();
510       }
511      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
512   }
513   //----------------------------------------------------------------
514
515   /*!
516   \brief Parse xml file and write information into file object
517   \param [in] node xmld node corresponding in xml file
518   */
519   void CFile::parse(xml::CXMLNode & node)
520   {
521      SuperClass::parse(node);
522
523      if (node.goToChildElement())
524      {
525        do
526        {
527           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
528           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
529        } while (node.goToNextElement()) ;
530        node.goToParentElement();
531      }
532
533   }
534   //----------------------------------------------------------------
535
536   /*!
537   \brief Represent a file in form of string with all its info
538   \return String
539   */
540   StdString CFile::toString(void) const
541   {
542      StdOStringStream oss;
543
544      oss << "<" << CFile::GetName() << " ";
545      if (this->hasId())
546         oss << " id=\"" << this->getId() << "\" ";
547      oss << SuperClassAttribute::toString() << ">" << std::endl;
548      if (this->getVirtualFieldGroup() != NULL)
549         oss << *this->getVirtualFieldGroup() << std::endl;
550      oss << "</" << CFile::GetName() << " >";
551      return (oss.str());
552   }
553
554   //----------------------------------------------------------------
555
556   /*!
557   \brief Find all inheritace among objects in a file.
558   \param [in] apply (true) write attributes of parent into ones of child if they are empty
559                     (false) write attributes of parent into a new container of child
560   \param [in] parent
561   */
562   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
563   {
564      SuperClassAttribute::setAttributes(parent,apply);
565      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
566      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
567   }
568
569   //----------------------------------------------------------------
570
571//   void CFile::processEnabledFile(void)
572//   {
573//     if (output_freq.isEmpty()) ERROR("void CFile::processEnabledFile(void)",
574//                                       <<"File attribute <<output_freq>> is undefined");
575//     solveFieldRefInheritance(true) ;
576//     getEnabledFields() ;
577//     processEnabledFields() ;
578//   }
579
580//   void CFile::processEnabledFields(void)
581//   {
582//      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
583//      {
584//        this->enabledFields[i]->processEnabledField() ;
585//      }
586//   }
587
588   /*!
589   \brief Resolve all reference of active fields.
590      In order to know exactly which data each active field has, a search for all its
591   reference to find its parents or/and its base reference object must be done. Moreover
592   during this search, there are some information that can only be sent to server AFTER
593   all information of active fields are created on server side, e.g: checking mask or index
594   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
595   */
596   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
597   {
598     int size = this->enabledFields.size();
599     for (int i = 0; i < size; ++i)
600     {
601       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
602     }
603   }
604
605   /*!
606   \brief Contruct all expression related to active fields.
607      Each field can do some expressions which appear on the xml file, and itself can be
608   a result of an expression among some other fields. This function builds all possible expression
609   relating to active fields.
610   */
611   void CFile::buildAllExpressionOfEnabledFields()
612   {
613     int size = this->enabledFields.size();
614     for (int i = 0; i < size; ++i)
615     {
616       this->enabledFields[i]->buildAllExpressionEnabledField();
617     }
618   }
619
620   /*!
621     Prefetching the data for enabled fields read from file.
622   */
623   void CFile::prefetchEnabledReadModeFields(void)
624   {
625     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
626       return;
627
628     int size = this->enabledFields.size();
629     for (int i = 0; i < size; ++i)
630       this->enabledFields[i]->sendReadDataRequest();
631   }
632
633   /*!
634     Prefetching the data for enabled fields read from file whose data is out-of-date.
635   */
636   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
637   {
638     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
639       return;
640
641     int size = this->enabledFields.size();
642     for (int i = 0; i < size; ++i)
643       this->enabledFields[i]->sendReadDataRequestIfNeeded();
644   }
645
646   void CFile::solveFieldRefInheritance(bool apply)
647   {
648      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
649      std::vector<CField*> allF = this->getAllFields();
650      for (unsigned int i = 0; i < allF.size(); i++)
651         allF[i]->solveRefInheritance(apply);
652   }
653
654   //----------------------------------------------------------------
655
656   void CFile::solveEFGridRef(void)
657   {
658      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
659         this->enabledFields[i]->solveGridReference();
660   }
661
662   //----------------------------------------------------------------
663
664   void CFile::solveEFOperation(void)
665   {
666      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
667         this->enabledFields[i]->solveOperation();
668   }
669
670   void CFile::solveEFExpression(void)
671   {
672      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
673         this->enabledFields[i]->buildExpression();
674   }
675
676   /*!
677   \brief Add a field into file.
678      A field is added into file and it will be written out if the file is enabled and
679   level of this field is smaller than level_output. A new field won't be created if one
680   with id has already existed
681   \param [in] id String identity of new field
682   \return Pointer to added (or already existed) field
683   */
684   CField* CFile::addField(const string& id)
685   {
686     return vFieldGroup->createChild(id) ;
687   }
688
689   /*!
690   \brief Add a field group into file.
691      A field group is added into file and it will play a role as parents for fields.
692   A new field group won't be created if one with id has already existed
693   \param [in] id String identity of new field group
694   \return Pointer to added (or already existed) field group
695   */
696   CFieldGroup* CFile::addFieldGroup(const string& id)
697   {
698     return vFieldGroup->createChildGroup(id) ;
699   }
700
701   /*!
702   \brief Add a variable into file.
703      A variable is added into file and if one with id has already existed, pointer to
704   it will be returned.
705      Variable as long as attributes are information container of file.
706   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
707   to fill in (extra) information for a file.
708   \param [in] id String identity of new variable
709   \return Pointer to added (or already existed) variable
710   */
711   CVariable* CFile::addVariable(const string& id)
712   {
713     return vVariableGroup->createChild(id) ;
714   }
715
716   /*!
717   \brief Add a variable group into file.
718      A variable group is added into file and it will play a role as parents for variables.
719   A new variable group won't be created if one with id has already existed
720   \param [in] id String identity of new variable group
721   \return Pointer to added (or already existed) variable group
722   */
723   CVariableGroup* CFile::addVariableGroup(const string& id)
724   {
725     return vVariableGroup->createChildGroup(id) ;
726   }
727
728   /*!
729   \brief Send a message to create a field on server side
730   \param[in] id String identity of field that will be created on server
731   */
732   void CFile::sendAddField(const string& id)
733   {
734    CContext* context=CContext::getCurrent() ;
735
736    if (! context->hasServer )
737    {
738       CContextClient* client=context->client ;
739
740       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;
741       if (client->isServerLeader())
742       {
743         CMessage msg ;
744         msg<<this->getId() ;
745         msg<<id ;
746         const std::list<int>& ranks = client->getRanksServerLeader();
747         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
748           event.push(*itRank,1,msg);
749         client->sendEvent(event) ;
750       }
751       else client->sendEvent(event) ;
752    }
753
754   }
755
756   /*!
757   \brief Send a message to create a field group on server side
758   \param[in] id String identity of field group that will be created on server
759   */
760   void CFile::sendAddFieldGroup(const string& id)
761   {
762    CContext* context=CContext::getCurrent() ;
763    if (! context->hasServer )
764    {
765       CContextClient* client=context->client ;
766
767       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;
768       if (client->isServerLeader())
769       {
770         CMessage msg ;
771         msg<<this->getId() ;
772         msg<<id ;
773         const std::list<int>& ranks = client->getRanksServerLeader();
774         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
775           event.push(*itRank,1,msg);
776         client->sendEvent(event) ;
777       }
778       else client->sendEvent(event) ;
779    }
780
781   }
782
783   /*!
784   \brief Receive a message annoucing the creation of a field on server side
785   \param[in] event Received event
786   */
787   void CFile::recvAddField(CEventServer& event)
788   {
789
790      CBufferIn* buffer=event.subEvents.begin()->buffer;
791      string id;
792      *buffer>>id ;
793      get(id)->recvAddField(*buffer) ;
794   }
795
796   /*!
797   \brief Receive a message annoucing the creation of a field on server side
798   \param[in] buffer Buffer containing message
799   */
800   void CFile::recvAddField(CBufferIn& buffer)
801   {
802      string id ;
803      buffer>>id ;
804      addField(id) ;
805   }
806
807   /*!
808   \brief Receive a message annoucing the creation of a field group on server side
809   \param[in] event Received event
810   */
811   void CFile::recvAddFieldGroup(CEventServer& event)
812   {
813
814      CBufferIn* buffer=event.subEvents.begin()->buffer;
815      string id;
816      *buffer>>id ;
817      get(id)->recvAddFieldGroup(*buffer) ;
818   }
819
820   /*!
821   \brief Receive a message annoucing the creation of a field group on server side
822   \param[in] buffer Buffer containing message
823   */
824   void CFile::recvAddFieldGroup(CBufferIn& buffer)
825   {
826      string id ;
827      buffer>>id ;
828      addFieldGroup(id) ;
829   }
830
831   /*!
832   \brief Send messages to duplicate all variables on server side
833      Because each variable has also its attributes. So first thing to do is replicate
834   all these attributes on server side. Because variable can have a value, the second thing
835   is to duplicate this value on server, too.
836   */
837   void CFile::sendAddAllVariables()
838   {
839     if (!getAllVariables().empty())
840     {
841       // Firstly, it's necessary to add virtual variable group
842       sendAddVariableGroup(getVirtualVariableGroup()->getId());
843
844       // Okie, now we can add to this variable group
845       std::vector<CVariable*> allVar = getAllVariables();
846       std::vector<CVariable*>::const_iterator it = allVar.begin();
847       std::vector<CVariable*>::const_iterator itE = allVar.end();
848
849       for (; it != itE; ++it)
850       {
851         this->sendAddVariable((*it)->getId());
852         (*it)->sendAllAttributesToServer();
853         (*it)->sendValue();
854       }
855     }
856   }
857
858   /*!
859   \brief Send a message to create a variable on server side
860      A variable always belongs to a variable group
861   \param[in] id String identity of variable that will be created on server
862   */
863   void CFile::sendAddVariable(const string& id)
864   {
865    CContext* context=CContext::getCurrent() ;
866
867    if (! context->hasServer )
868    {
869       CContextClient* client=context->client ;
870
871       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE) ;
872       if (client->isServerLeader())
873       {
874         CMessage msg ;
875         msg<<this->getId() ;
876         msg<<id ;
877         const std::list<int>& ranks = client->getRanksServerLeader();
878         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
879           event.push(*itRank,1,msg);
880         client->sendEvent(event) ;
881       }
882       else client->sendEvent(event) ;
883    }
884
885   }
886
887   /*!
888   \brief Send a message to create a variable group on server side
889   \param[in] id String identity of variable group that will be created on server
890   */
891   void CFile::sendAddVariableGroup(const string& id)
892   {
893    CContext* context=CContext::getCurrent() ;
894    if (! context->hasServer )
895    {
896       CContextClient* client=context->client ;
897
898       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP) ;
899       if (client->isServerLeader())
900       {
901         CMessage msg ;
902         msg<<this->getId() ;
903         msg<<id ;
904         const std::list<int>& ranks = client->getRanksServerLeader();
905         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
906           event.push(*itRank,1,msg);
907         client->sendEvent(event) ;
908       }
909       else client->sendEvent(event) ;
910    }
911
912   }
913
914   /*!
915   \brief Receive a message annoucing the creation of a variable on server side
916   \param[in] event Received event
917   */
918   void CFile::recvAddVariable(CEventServer& event)
919   {
920
921      CBufferIn* buffer=event.subEvents.begin()->buffer;
922      string id;
923      *buffer>>id ;
924      get(id)->recvAddVariable(*buffer) ;
925   }
926
927   /*!
928   \brief Receive a message annoucing the creation of a variable on server side
929   \param[in] buffer Buffer containing message
930   */
931   void CFile::recvAddVariable(CBufferIn& buffer)
932   {
933      string id ;
934      buffer>>id ;
935      addVariable(id) ;
936   }
937
938   /*!
939   \brief Receive a message annoucing the creation of a variable group on server side
940   \param[in] event Received event
941   */
942   void CFile::recvAddVariableGroup(CEventServer& event)
943   {
944
945      CBufferIn* buffer=event.subEvents.begin()->buffer;
946      string id;
947      *buffer>>id ;
948      get(id)->recvAddVariableGroup(*buffer) ;
949   }
950
951   /*!
952   \brief Receive a message annoucing the creation of a variable group on server side
953   \param[in] buffer Buffer containing message
954   */
955   void CFile::recvAddVariableGroup(CBufferIn& buffer)
956   {
957      string id ;
958      buffer>>id ;
959      addVariableGroup(id) ;
960   }
961
962   /*!
963     \brief Sending all active (enabled) fields from client to server.
964   Each field is identified uniquely by its string identity. Not only should we
965   send the id to server but also we need to send ids of reference domain and reference axis.
966   With these two id, it's easier to make reference to grid where all data should be written.
967   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
968   */
969   void CFile::sendEnabledFields()
970   {
971     int size = this->enabledFields.size();
972     CField* fieldPtr(0);
973     for (int i = 0; i < size; ++i)
974     {
975       fieldPtr = this->enabledFields[i];
976       if (fieldPtr->name.isEmpty()) fieldPtr->name.setValue(fieldPtr->getBaseFieldReference()->getId());
977       this->sendAddField(fieldPtr->getId());
978       fieldPtr->sendAllAttributesToServer();
979       fieldPtr->sendAddAllVariables();
980     }
981   }
982
983   /*!
984   \brief Dispatch event received from client
985      Whenever a message is received in buffer of server, it will be processed depending on
986   its event type. A new event type should be added in the switch list to make sure
987   it processed on server side.
988   \param [in] event: Received message
989   */
990   bool CFile::dispatchEvent(CEventServer& event)
991   {
992      if (SuperClass::dispatchEvent(event)) return true ;
993      else
994      {
995        switch(event.type)
996        {
997           case EVENT_ID_ADD_FIELD :
998             recvAddField(event) ;
999             return true ;
1000             break ;
1001
1002           case EVENT_ID_ADD_FIELD_GROUP :
1003             recvAddFieldGroup(event) ;
1004             return true ;
1005             break ;
1006
1007            case EVENT_ID_ADD_VARIABLE :
1008             recvAddVariable(event) ;
1009             return true ;
1010             break ;
1011
1012           case EVENT_ID_ADD_VARIABLE_GROUP :
1013             recvAddVariableGroup(event) ;
1014             return true ;
1015             break ;
1016           default :
1017              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
1018           return false ;
1019        }
1020      }
1021   }
1022
1023
1024
1025
1026   ///---------------------------------------------------------------
1027
1028} // namespace xios
Note: See TracBrowser for help on using the repository browser.