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

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

Start using the filter infrastructure to read and write fields.

Note that currently only the simple cases are working. References and all types of operations are disabled.

  • 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: 33.2 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<CAxis*> setAxis;
227      set<CDomain*> setDomains;
228
229      std::vector<CField*>::iterator it, end = this->enabledFields.end();
230      for (it = this->enabledFields.begin(); it != end; it++)
231      {
232         CField* field = *it;
233         allDomainEmpty &= !field->grid->doGridHaveDataToWrite();
234         std::vector<CAxis*> vecAxis = field->grid->getAxis();
235         for (size_t i = 0; i < vecAxis.size(); ++i)
236            setAxis.insert(vecAxis[i]);
237         std::vector<CDomain*> vecDomains = field->grid->getDomains();
238         for (size_t i = 0; i < vecDomains.size(); ++i)
239            setDomains.insert(vecDomains[i]);
240      }
241      nbAxis = setAxis.size();
242      nbDomains = setDomains.size();
243
244      // create sub communicator for file
245      int color=allDomainEmpty?0:1 ;
246      MPI_Comm_split(server->intraComm,color,server->intraCommRank,&fileComm) ;
247      if (allDomainEmpty) MPI_Comm_free(&fileComm) ;
248      //
249
250    }
251
252    //! Verify state of a file
253    void CFile::checkFile(void)
254    {
255      if (mode.isEmpty() || mode.getValue() == mode_attr::write)
256      {
257        if (!isOpen) createHeader();
258        checkSync();
259      }
260      else
261      {
262        if (!isOpen) openInReadMode();
263      }
264      checkSplit();
265    }
266
267    /*!
268    \brief Verify if synchronisation should be done
269        If syn option is enabled, syn frequence and current time will be used to
270    calculate the moment to syn file(s)
271    \return True if it is the moment to synchronize file, otherwise false
272    */
273   bool CFile::checkSync(void)
274   {
275     CContext* context = CContext::getCurrent() ;
276     const CDate& currentDate = context->calendar->getCurrentDate() ;
277     if (!sync_freq.isEmpty())
278     {
279       if (*lastSync + sync_freq.getValue() <= currentDate)
280       {
281         *lastSync=currentDate ;
282         data_out->syncFile() ;
283         return true ;
284        }
285      }
286      return false ;
287    }
288
289    /*!
290    \brief Verify if splitting should be done
291        If split option is enabled, split frequence and current time will be used to
292    calculate the moment to split file
293    \return True if it is the moment to split file, otherwise false
294    */
295    bool CFile::checkSplit(void)
296    {
297      CContext* context = CContext::getCurrent() ;
298      const CDate& currentDate = context->calendar->getCurrentDate() ;
299      if (!split_freq.isEmpty())
300      {
301        if (currentDate > *lastSplit + split_freq.getValue())
302        {
303          *lastSplit = *lastSplit + split_freq.getValue();
304          std::vector<CField*>::iterator it, end = this->enabledFields.end();
305          for (it = this->enabledFields.begin(); it != end; it++)
306          {
307            (*it)->resetNStep();
308            (*it)->resetNStepMax();
309          }
310          if (mode.isEmpty() || mode.getValue() == mode_attr::write)
311            createHeader() ;
312          else
313            openInReadMode();
314          return true ;
315        }
316      }
317      return false ;
318    }
319
320   /*!
321   \brief Create header of netcdf file
322   There are some information to fill in header of each netcdf.
323   */
324   void CFile::createHeader(void)
325   {
326      CContext* context = CContext::getCurrent() ;
327      CContextServer* server=context->server ;
328
329      if (!allDomainEmpty)
330      {
331         StdString filename = (!name.isEmpty()) ?   name.getValue() : getId();
332         StdOStringStream oss;
333         oss << filename;
334         if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
335
336         if (!split_freq.isEmpty())
337         {
338           string splitFormat ;
339           if (split_freq_format.isEmpty())
340           {
341             if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
342             else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
343             else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
344             else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
345             else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
346             else splitFormat = "%y";
347           }
348           else splitFormat=split_freq_format ;
349           oss << "_" << lastSplit->getStr(splitFormat)
350               << "-" << (*lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
351         }
352
353        bool append = !this->append.isEmpty() && this->append.getValue();
354
355         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
356
357         bool multifile=true ;
358         if (!type.isEmpty())
359         {
360           if (type==type_attr::one_file) multifile=false ;
361           else if (type==type_attr::multiple_file) multifile=true ;
362
363         }
364#ifndef USING_NETCDF_PAR
365         if (!multifile)
366         {
367            info(0)<<"!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : "<<filename<<" ..."<<endl ;
368            multifile=true ;
369          }
370#endif
371         if (multifile)
372         {
373            int commSize, commRank ;
374            MPI_Comm_size(fileComm,&commSize) ;
375            MPI_Comm_rank(fileComm,&commRank) ;
376
377            if (server->intraCommSize > 1)
378            {
379              oss << "_"  ;
380              int width=0 ; int n=commSize-1 ;
381              while(n != 0) { n=n/10 ; width++ ;}
382              if (!min_digits.isEmpty())
383                if (width<min_digits) width=min_digits ;
384              oss.width(width) ;
385              oss.fill('0') ;
386              oss<<right<< commRank;
387            }
388         }
389         oss << ".nc";
390
391         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
392
393         if (isOpen) data_out->closeFile();
394
395        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), append, useClassicFormat,
396                                                              fileComm, multifile, isCollective));
397        isOpen = true;
398
399        data_out->writeFile(CFile::get(this));
400
401        // Do not recreate the file structure if opening an existing file
402        if (!data_out->IsInAppendMode())
403        {
404          std::vector<CField*>::iterator it, end = this->enabledFields.end();
405          for (it = this->enabledFields.begin(); it != end; it++)
406          {
407            CField* field = *it;
408            this->data_out->writeFieldGrid(field);
409          }
410          this->data_out->writeTimeDimension();
411
412          for (it = this->enabledFields.begin(); it != end; it++)
413          {
414            CField* field = *it;
415            this->data_out->writeField(field);
416          }
417
418          vector<CVariable*> listVars = getAllVariables() ;
419          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
420            this->data_out->writeAttribute(*it);
421
422          this->data_out->definition_end();
423        }
424      }
425   }
426
427  /*!
428  \brief Open an existing NetCDF file in read-only mode
429  */
430  void CFile::openInReadMode(void)
431  {
432    CContext* context = CContext::getCurrent();
433    CContextServer* server=context->server;
434
435    if (!allDomainEmpty)
436    {
437      StdString filename = (!name.isEmpty()) ? name.getValue() : getId();
438      StdOStringStream oss;
439      oss << filename;
440      if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
441
442      if (!split_freq.isEmpty())
443      {
444        string splitFormat;
445        if (split_freq_format.isEmpty())
446        {
447          if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
448          else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
449          else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
450          else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
451          else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
452          else splitFormat = "%y";
453        }
454        else splitFormat=split_freq_format;
455        oss << "_" << lastSplit->getStr(splitFormat)
456        << "-" << (*lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
457      }
458
459      bool multifile = true;
460      if (!type.isEmpty())
461      {
462        if (type == type_attr::one_file) multifile = false;
463        else if (type == type_attr::multiple_file) multifile = true;
464      }
465  #ifndef USING_NETCDF_PAR
466      if (!multifile)
467      {
468        info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
469        multifile = true;
470      }
471  #endif
472      if (multifile)
473      {
474        int commSize, commRank;
475        MPI_Comm_size(fileComm, &commSize);
476        MPI_Comm_rank(fileComm, &commRank);
477
478        if (server->intraCommSize > 1)
479        {
480          oss << "_" ;
481          int width = 0, n = commSize - 1;
482          while (n != 0) { n = n / 10; width++; }
483          if (!min_digits.isEmpty() && width < min_digits)
484            width = min_digits;
485          oss.width(width);
486          oss.fill('0');
487          oss << right << commRank;
488        }
489      }
490      oss << ".nc";
491
492      bool isCollective = par_access.isEmpty() || par_access == par_access_attr::collective;
493
494      if (isOpen) data_out->closeFile();
495
496      data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective));
497      isOpen = true;
498    }
499  }
500
501   //! Close file
502   void CFile::close(void)
503   {
504     delete lastSync ;
505     delete lastSplit ;
506     if (!allDomainEmpty)
507       if (isOpen)
508       {
509         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
510          this->data_out->closeFile();
511         else
512          this->data_in->closeFile();
513       }
514      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm) ;
515   }
516   //----------------------------------------------------------------
517
518   /*!
519   \brief Parse xml file and write information into file object
520   \param [in] node xmld node corresponding in xml file
521   */
522   void CFile::parse(xml::CXMLNode & node)
523   {
524      SuperClass::parse(node);
525
526      if (node.goToChildElement())
527      {
528        do
529        {
530           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
531           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
532        } while (node.goToNextElement()) ;
533        node.goToParentElement();
534      }
535
536   }
537   //----------------------------------------------------------------
538
539   /*!
540   \brief Represent a file in form of string with all its info
541   \return String
542   */
543   StdString CFile::toString(void) const
544   {
545      StdOStringStream oss;
546
547      oss << "<" << CFile::GetName() << " ";
548      if (this->hasId())
549         oss << " id=\"" << this->getId() << "\" ";
550      oss << SuperClassAttribute::toString() << ">" << std::endl;
551      if (this->getVirtualFieldGroup() != NULL)
552         oss << *this->getVirtualFieldGroup() << std::endl;
553      oss << "</" << CFile::GetName() << " >";
554      return (oss.str());
555   }
556
557   //----------------------------------------------------------------
558
559   /*!
560   \brief Find all inheritace among objects in a file.
561   \param [in] apply (true) write attributes of parent into ones of child if they are empty
562                     (false) write attributes of parent into a new container of child
563   \param [in] parent
564   */
565   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
566   {
567      SuperClassAttribute::setAttributes(parent,apply);
568      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
569      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
570   }
571
572   //----------------------------------------------------------------
573
574//   void CFile::processEnabledFile(void)
575//   {
576//     if (output_freq.isEmpty()) ERROR("void CFile::processEnabledFile(void)",
577//                                       <<"File attribute <<output_freq>> is undefined");
578//     solveFieldRefInheritance(true) ;
579//     getEnabledFields() ;
580//     processEnabledFields() ;
581//   }
582
583//   void CFile::processEnabledFields(void)
584//   {
585//      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
586//      {
587//        this->enabledFields[i]->processEnabledField() ;
588//      }
589//   }
590
591   /*!
592   \brief Resolve all reference of active fields.
593      In order to know exactly which data each active field has, a search for all its
594   reference to find its parents or/and its base reference object must be done. Moreover
595   during this search, there are some information that can only be sent to server AFTER
596   all information of active fields are created on server side, e.g: checking mask or index
597   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
598   */
599   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
600   {
601     int size = this->enabledFields.size();
602     for (int i = 0; i < size; ++i)
603     {
604       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
605     }
606   }
607
608   /*!
609   \brief Contruct all expression related to active fields.
610      Each field can do some expressions which appear on the xml file, and itself can be
611   a result of an expression among some other fields. This function builds all possible expression
612   relating to active fields.
613   */
614   void CFile::buildAllExpressionOfEnabledFields()
615   {
616     int size = this->enabledFields.size();
617     for (int i = 0; i < size; ++i)
618     {
619       this->enabledFields[i]->buildAllExpressionEnabledField();
620     }
621   }
622
623   /*!
624    * Constructs the filter graph for each active field.
625    *
626    * \param gc the garbage collector to use when building the filter graph
627    */
628   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
629   {
630     int size = this->enabledFields.size();
631     for (int i = 0; i < size; ++i)
632     {
633       this->enabledFields[i]->buildFilterGraph(gc, true);
634     }
635   }
636
637   /*!
638     Prefetching the data for enabled fields read from file.
639   */
640   void CFile::prefetchEnabledReadModeFields(void)
641   {
642     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
643       return;
644
645     int size = this->enabledFields.size();
646     for (int i = 0; i < size; ++i)
647       this->enabledFields[i]->sendReadDataRequest();
648   }
649
650   /*!
651     Prefetching the data for enabled fields read from file whose data is out-of-date.
652   */
653   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
654   {
655     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
656       return;
657
658     int size = this->enabledFields.size();
659     for (int i = 0; i < size; ++i)
660       this->enabledFields[i]->sendReadDataRequestIfNeeded();
661   }
662
663   void CFile::solveFieldRefInheritance(bool apply)
664   {
665      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
666      std::vector<CField*> allF = this->getAllFields();
667      for (unsigned int i = 0; i < allF.size(); i++)
668         allF[i]->solveRefInheritance(apply);
669   }
670
671   //----------------------------------------------------------------
672
673   void CFile::solveEFGridRef(void)
674   {
675      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
676         this->enabledFields[i]->solveGridReference();
677   }
678
679   //----------------------------------------------------------------
680
681   void CFile::solveEFOperation(void)
682   {
683      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
684         this->enabledFields[i]->solveOperation();
685   }
686
687   void CFile::solveEFExpression(void)
688   {
689      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
690         this->enabledFields[i]->buildExpression();
691   }
692
693   /*!
694   \brief Add a field into file.
695      A field is added into file and it will be written out if the file is enabled and
696   level of this field is smaller than level_output. A new field won't be created if one
697   with id has already existed
698   \param [in] id String identity of new field
699   \return Pointer to added (or already existed) field
700   */
701   CField* CFile::addField(const string& id)
702   {
703     return vFieldGroup->createChild(id) ;
704   }
705
706   /*!
707   \brief Add a field group into file.
708      A field group is added into file and it will play a role as parents for fields.
709   A new field group won't be created if one with id has already existed
710   \param [in] id String identity of new field group
711   \return Pointer to added (or already existed) field group
712   */
713   CFieldGroup* CFile::addFieldGroup(const string& id)
714   {
715     return vFieldGroup->createChildGroup(id) ;
716   }
717
718   /*!
719   \brief Add a variable into file.
720      A variable is added into file and if one with id has already existed, pointer to
721   it will be returned.
722      Variable as long as attributes are information container of file.
723   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
724   to fill in (extra) information for a file.
725   \param [in] id String identity of new variable
726   \return Pointer to added (or already existed) variable
727   */
728   CVariable* CFile::addVariable(const string& id)
729   {
730     return vVariableGroup->createChild(id) ;
731   }
732
733   /*!
734   \brief Add a variable group into file.
735      A variable group is added into file and it will play a role as parents for variables.
736   A new variable group won't be created if one with id has already existed
737   \param [in] id String identity of new variable group
738   \return Pointer to added (or already existed) variable group
739   */
740   CVariableGroup* CFile::addVariableGroup(const string& id)
741   {
742     return vVariableGroup->createChildGroup(id) ;
743   }
744
745   /*!
746   \brief Send a message to create a field on server side
747   \param[in] id String identity of field that will be created on server
748   */
749   void CFile::sendAddField(const string& id)
750   {
751    CContext* context=CContext::getCurrent() ;
752
753    if (! context->hasServer )
754    {
755       CContextClient* client=context->client ;
756
757       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;
758       if (client->isServerLeader())
759       {
760         CMessage msg ;
761         msg<<this->getId() ;
762         msg<<id ;
763         const std::list<int>& ranks = client->getRanksServerLeader();
764         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
765           event.push(*itRank,1,msg);
766         client->sendEvent(event) ;
767       }
768       else client->sendEvent(event) ;
769    }
770
771   }
772
773   /*!
774   \brief Send a message to create a field group on server side
775   \param[in] id String identity of field group that will be created on server
776   */
777   void CFile::sendAddFieldGroup(const string& id)
778   {
779    CContext* context=CContext::getCurrent() ;
780    if (! context->hasServer )
781    {
782       CContextClient* client=context->client ;
783
784       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;
785       if (client->isServerLeader())
786       {
787         CMessage msg ;
788         msg<<this->getId() ;
789         msg<<id ;
790         const std::list<int>& ranks = client->getRanksServerLeader();
791         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
792           event.push(*itRank,1,msg);
793         client->sendEvent(event) ;
794       }
795       else client->sendEvent(event) ;
796    }
797
798   }
799
800   /*!
801   \brief Receive a message annoucing the creation of a field on server side
802   \param[in] event Received event
803   */
804   void CFile::recvAddField(CEventServer& event)
805   {
806
807      CBufferIn* buffer=event.subEvents.begin()->buffer;
808      string id;
809      *buffer>>id ;
810      get(id)->recvAddField(*buffer) ;
811   }
812
813   /*!
814   \brief Receive a message annoucing the creation of a field on server side
815   \param[in] buffer Buffer containing message
816   */
817   void CFile::recvAddField(CBufferIn& buffer)
818   {
819      string id ;
820      buffer>>id ;
821      addField(id) ;
822   }
823
824   /*!
825   \brief Receive a message annoucing the creation of a field group on server side
826   \param[in] event Received event
827   */
828   void CFile::recvAddFieldGroup(CEventServer& event)
829   {
830
831      CBufferIn* buffer=event.subEvents.begin()->buffer;
832      string id;
833      *buffer>>id ;
834      get(id)->recvAddFieldGroup(*buffer) ;
835   }
836
837   /*!
838   \brief Receive a message annoucing the creation of a field group on server side
839   \param[in] buffer Buffer containing message
840   */
841   void CFile::recvAddFieldGroup(CBufferIn& buffer)
842   {
843      string id ;
844      buffer>>id ;
845      addFieldGroup(id) ;
846   }
847
848   /*!
849   \brief Send messages to duplicate all variables on server side
850      Because each variable has also its attributes. So first thing to do is replicate
851   all these attributes on server side. Because variable can have a value, the second thing
852   is to duplicate this value on server, too.
853   */
854   void CFile::sendAddAllVariables()
855   {
856     if (!getAllVariables().empty())
857     {
858       // Firstly, it's necessary to add virtual variable group
859       sendAddVariableGroup(getVirtualVariableGroup()->getId());
860
861       // Okie, now we can add to this variable group
862       std::vector<CVariable*> allVar = getAllVariables();
863       std::vector<CVariable*>::const_iterator it = allVar.begin();
864       std::vector<CVariable*>::const_iterator itE = allVar.end();
865
866       for (; it != itE; ++it)
867       {
868         this->sendAddVariable((*it)->getId());
869         (*it)->sendAllAttributesToServer();
870         (*it)->sendValue();
871       }
872     }
873   }
874
875   /*!
876   \brief Send a message to create a variable on server side
877      A variable always belongs to a variable group
878   \param[in] id String identity of variable that will be created on server
879   */
880   void CFile::sendAddVariable(const string& id)
881   {
882    CContext* context=CContext::getCurrent() ;
883
884    if (! context->hasServer )
885    {
886       CContextClient* client=context->client ;
887
888       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE) ;
889       if (client->isServerLeader())
890       {
891         CMessage msg ;
892         msg<<this->getId() ;
893         msg<<id ;
894         const std::list<int>& ranks = client->getRanksServerLeader();
895         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
896           event.push(*itRank,1,msg);
897         client->sendEvent(event) ;
898       }
899       else client->sendEvent(event) ;
900    }
901
902   }
903
904   /*!
905   \brief Send a message to create a variable group on server side
906   \param[in] id String identity of variable group that will be created on server
907   */
908   void CFile::sendAddVariableGroup(const string& id)
909   {
910    CContext* context=CContext::getCurrent() ;
911    if (! context->hasServer )
912    {
913       CContextClient* client=context->client ;
914
915       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP) ;
916       if (client->isServerLeader())
917       {
918         CMessage msg ;
919         msg<<this->getId() ;
920         msg<<id ;
921         const std::list<int>& ranks = client->getRanksServerLeader();
922         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
923           event.push(*itRank,1,msg);
924         client->sendEvent(event) ;
925       }
926       else client->sendEvent(event) ;
927    }
928
929   }
930
931   /*!
932   \brief Receive a message annoucing the creation of a variable on server side
933   \param[in] event Received event
934   */
935   void CFile::recvAddVariable(CEventServer& event)
936   {
937
938      CBufferIn* buffer=event.subEvents.begin()->buffer;
939      string id;
940      *buffer>>id ;
941      get(id)->recvAddVariable(*buffer) ;
942   }
943
944   /*!
945   \brief Receive a message annoucing the creation of a variable on server side
946   \param[in] buffer Buffer containing message
947   */
948   void CFile::recvAddVariable(CBufferIn& buffer)
949   {
950      string id ;
951      buffer>>id ;
952      addVariable(id) ;
953   }
954
955   /*!
956   \brief Receive a message annoucing the creation of a variable group on server side
957   \param[in] event Received event
958   */
959   void CFile::recvAddVariableGroup(CEventServer& event)
960   {
961
962      CBufferIn* buffer=event.subEvents.begin()->buffer;
963      string id;
964      *buffer>>id ;
965      get(id)->recvAddVariableGroup(*buffer) ;
966   }
967
968   /*!
969   \brief Receive a message annoucing the creation of a variable group on server side
970   \param[in] buffer Buffer containing message
971   */
972   void CFile::recvAddVariableGroup(CBufferIn& buffer)
973   {
974      string id ;
975      buffer>>id ;
976      addVariableGroup(id) ;
977   }
978
979   /*!
980     \brief Sending all active (enabled) fields from client to server.
981   Each field is identified uniquely by its string identity. Not only should we
982   send the id to server but also we need to send ids of reference domain and reference axis.
983   With these two id, it's easier to make reference to grid where all data should be written.
984   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
985   */
986   void CFile::sendEnabledFields()
987   {
988     int size = this->enabledFields.size();
989     CField* fieldPtr(0);
990     for (int i = 0; i < size; ++i)
991     {
992       fieldPtr = this->enabledFields[i];
993       if (fieldPtr->name.isEmpty()) fieldPtr->name.setValue(fieldPtr->getBaseFieldReference()->getId());
994       this->sendAddField(fieldPtr->getId());
995       fieldPtr->sendAllAttributesToServer();
996       fieldPtr->sendAddAllVariables();
997     }
998   }
999
1000   /*!
1001   \brief Dispatch event received from client
1002      Whenever a message is received in buffer of server, it will be processed depending on
1003   its event type. A new event type should be added in the switch list to make sure
1004   it processed on server side.
1005   \param [in] event: Received message
1006   */
1007   bool CFile::dispatchEvent(CEventServer& event)
1008   {
1009      if (SuperClass::dispatchEvent(event)) return true ;
1010      else
1011      {
1012        switch(event.type)
1013        {
1014           case EVENT_ID_ADD_FIELD :
1015             recvAddField(event) ;
1016             return true ;
1017             break ;
1018
1019           case EVENT_ID_ADD_FIELD_GROUP :
1020             recvAddFieldGroup(event) ;
1021             return true ;
1022             break ;
1023
1024            case EVENT_ID_ADD_VARIABLE :
1025             recvAddVariable(event) ;
1026             return true ;
1027             break ;
1028
1029           case EVENT_ID_ADD_VARIABLE_GROUP :
1030             recvAddVariableGroup(event) ;
1031             return true ;
1032             break ;
1033           default :
1034              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
1035           return false ;
1036        }
1037      }
1038   }
1039
1040
1041
1042
1043   ///---------------------------------------------------------------
1044
1045} // namespace xios
Note: See TracBrowser for help on using the repository browser.