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

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

Add a new file attribute to give our users more control on the time counter.

The time_counter attribute can take one of the following values:

  • centered: use centered times for the time counter (previous behavior, used by default)
  • instant: use instant times for the time counter
  • record: use record indexes for the time counter
  • none: disable the output of the time counter completely.
  • 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: 31.6 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  = currentDate;
221      lastSplit = 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      if (time_counter.isEmpty()) time_counter.setValue(time_counter_attr::centered);
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     if (!allDomainEmpty)
505       if (isOpen)
506       {
507         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
508          this->data_out->closeFile();
509         else
510          this->data_in->closeFile();
511       }
512      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
513   }
514   //----------------------------------------------------------------
515
516   /*!
517   \brief Parse xml file and write information into file object
518   \param [in] node xmld node corresponding in xml file
519   */
520   void CFile::parse(xml::CXMLNode & node)
521   {
522      SuperClass::parse(node);
523
524      if (node.goToChildElement())
525      {
526        do
527        {
528           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
529           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
530        } while (node.goToNextElement());
531        node.goToParentElement();
532      }
533
534   }
535   //----------------------------------------------------------------
536
537   /*!
538   \brief Represent a file in form of string with all its info
539   \return String
540   */
541   StdString CFile::toString(void) const
542   {
543      StdOStringStream oss;
544
545      oss << "<" << CFile::GetName() << " ";
546      if (this->hasId())
547         oss << " id=\"" << this->getId() << "\" ";
548      oss << SuperClassAttribute::toString() << ">" << std::endl;
549      if (this->getVirtualFieldGroup() != NULL)
550         oss << *this->getVirtualFieldGroup() << std::endl;
551      oss << "</" << CFile::GetName() << " >";
552      return (oss.str());
553   }
554
555   //----------------------------------------------------------------
556
557   /*!
558   \brief Find all inheritace among objects in a file.
559   \param [in] apply (true) write attributes of parent into ones of child if they are empty
560                     (false) write attributes of parent into a new container of child
561   \param [in] parent
562   */
563   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
564   {
565      SuperClassAttribute::setAttributes(parent,apply);
566      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
567      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
568   }
569
570   //----------------------------------------------------------------
571
572   /*!
573   \brief Resolve all reference of active fields.
574      In order to know exactly which data each active field has, a search for all its
575   reference to find its parents or/and its base reference object must be done. Moreover
576   during this search, there are some information that can only be sent to server AFTER
577   all information of active fields are created on server side, e.g: checking mask or index
578   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
579   */
580   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
581   {
582     int size = this->enabledFields.size();
583     for (int i = 0; i < size; ++i)
584     {
585       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
586     }
587   }
588
589   /*!
590    * Constructs the filter graph for each active field.
591    *
592    * \param gc the garbage collector to use when building the filter graph
593    */
594   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
595   {
596     int size = this->enabledFields.size();
597     for (int i = 0; i < size; ++i)
598     {
599       this->enabledFields[i]->buildFilterGraph(gc, true);
600     }
601   }
602
603   /*!
604     Prefetching the data for enabled fields read from file.
605   */
606   void CFile::prefetchEnabledReadModeFields(void)
607   {
608     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
609       return;
610
611     int size = this->enabledFields.size();
612     for (int i = 0; i < size; ++i)
613       this->enabledFields[i]->sendReadDataRequest();
614   }
615
616   /*!
617     Prefetching the data for enabled fields read from file whose data is out-of-date.
618   */
619   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
620   {
621     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
622       return;
623
624     int size = this->enabledFields.size();
625     for (int i = 0; i < size; ++i)
626       this->enabledFields[i]->sendReadDataRequestIfNeeded();
627   }
628
629   void CFile::solveFieldRefInheritance(bool apply)
630   {
631      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
632      std::vector<CField*> allF = this->getAllFields();
633      for (unsigned int i = 0; i < allF.size(); i++)
634         allF[i]->solveRefInheritance(apply);
635   }
636
637   //----------------------------------------------------------------
638
639   /*!
640   \brief Add a field into file.
641      A field is added into file and it will be written out if the file is enabled and
642   level of this field is smaller than level_output. A new field won't be created if one
643   with id has already existed
644   \param [in] id String identity of new field
645   \return Pointer to added (or already existed) field
646   */
647   CField* CFile::addField(const string& id)
648   {
649     return vFieldGroup->createChild(id);
650   }
651
652   /*!
653   \brief Add a field group into file.
654      A field group is added into file and it will play a role as parents for fields.
655   A new field group won't be created if one with id has already existed
656   \param [in] id String identity of new field group
657   \return Pointer to added (or already existed) field group
658   */
659   CFieldGroup* CFile::addFieldGroup(const string& id)
660   {
661     return vFieldGroup->createChildGroup(id);
662   }
663
664   /*!
665   \brief Add a variable into file.
666      A variable is added into file and if one with id has already existed, pointer to
667   it will be returned.
668      Variable as long as attributes are information container of file.
669   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
670   to fill in (extra) information for a file.
671   \param [in] id String identity of new variable
672   \return Pointer to added (or already existed) variable
673   */
674   CVariable* CFile::addVariable(const string& id)
675   {
676     return vVariableGroup->createChild(id);
677   }
678
679   /*!
680   \brief Add a variable group into file.
681      A variable group is added into file and it will play a role as parents for variables.
682   A new variable group won't be created if one with id has already existed
683   \param [in] id String identity of new variable group
684   \return Pointer to added (or already existed) variable group
685   */
686   CVariableGroup* CFile::addVariableGroup(const string& id)
687   {
688     return vVariableGroup->createChildGroup(id);
689   }
690
691   /*!
692   \brief Send a message to create a field on server side
693   \param[in] id String identity of field that will be created on server
694   */
695   void CFile::sendAddField(const string& id)
696   {
697    CContext* context = CContext::getCurrent();
698
699    if (! context->hasServer )
700    {
701       CContextClient* client = context->client;
702
703       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
704       if (client->isServerLeader())
705       {
706         CMessage msg;
707         msg << this->getId();
708         msg << id;
709         const std::list<int>& ranks = client->getRanksServerLeader();
710         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
711           event.push(*itRank,1,msg);
712         client->sendEvent(event);
713       }
714       else client->sendEvent(event);
715    }
716
717   }
718
719   /*!
720   \brief Send a message to create a field group on server side
721   \param[in] id String identity of field group that will be created on server
722   */
723   void CFile::sendAddFieldGroup(const string& id)
724   {
725    CContext* context = CContext::getCurrent();
726    if (! context->hasServer )
727    {
728       CContextClient* client = context->client;
729
730       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
731       if (client->isServerLeader())
732       {
733         CMessage msg;
734         msg << this->getId();
735         msg << id;
736         const std::list<int>& ranks = client->getRanksServerLeader();
737         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
738           event.push(*itRank,1,msg);
739         client->sendEvent(event);
740       }
741       else client->sendEvent(event);
742    }
743
744   }
745
746   /*!
747   \brief Receive a message annoucing the creation of a field on server side
748   \param[in] event Received event
749   */
750   void CFile::recvAddField(CEventServer& event)
751   {
752
753      CBufferIn* buffer = event.subEvents.begin()->buffer;
754      string id;
755      *buffer>>id;
756      get(id)->recvAddField(*buffer);
757   }
758
759   /*!
760   \brief Receive a message annoucing the creation of a field on server side
761   \param[in] buffer Buffer containing message
762   */
763   void CFile::recvAddField(CBufferIn& buffer)
764   {
765      string id;
766      buffer>>id;
767      addField(id);
768   }
769
770   /*!
771   \brief Receive a message annoucing the creation of a field group on server side
772   \param[in] event Received event
773   */
774   void CFile::recvAddFieldGroup(CEventServer& event)
775   {
776
777      CBufferIn* buffer = event.subEvents.begin()->buffer;
778      string id;
779      *buffer>>id;
780      get(id)->recvAddFieldGroup(*buffer);
781   }
782
783   /*!
784   \brief Receive a message annoucing the creation of a field group on server side
785   \param[in] buffer Buffer containing message
786   */
787   void CFile::recvAddFieldGroup(CBufferIn& buffer)
788   {
789      string id;
790      buffer>>id;
791      addFieldGroup(id);
792   }
793
794   /*!
795   \brief Send messages to duplicate all variables on server side
796      Because each variable has also its attributes. So first thing to do is replicate
797   all these attributes on server side. Because variable can have a value, the second thing
798   is to duplicate this value on server, too.
799   */
800   void CFile::sendAddAllVariables()
801   {
802     if (!getAllVariables().empty())
803     {
804       // Firstly, it's necessary to add virtual variable group
805       sendAddVariableGroup(getVirtualVariableGroup()->getId());
806
807       // Okie, now we can add to this variable group
808       std::vector<CVariable*> allVar = getAllVariables();
809       std::vector<CVariable*>::const_iterator it = allVar.begin();
810       std::vector<CVariable*>::const_iterator itE = allVar.end();
811
812       for (; it != itE; ++it)
813       {
814         this->sendAddVariable((*it)->getId());
815         (*it)->sendAllAttributesToServer();
816         (*it)->sendValue();
817       }
818     }
819   }
820
821   /*!
822   \brief Send a message to create a variable on server side
823      A variable always belongs to a variable group
824   \param[in] id String identity of variable that will be created on server
825   */
826   void CFile::sendAddVariable(const string& id)
827   {
828    CContext* context = CContext::getCurrent();
829
830    if (! context->hasServer )
831    {
832       CContextClient* client = context->client;
833
834       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
835       if (client->isServerLeader())
836       {
837         CMessage msg;
838         msg << this->getId();
839         msg << id;
840         const std::list<int>& ranks = client->getRanksServerLeader();
841         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
842           event.push(*itRank,1,msg);
843         client->sendEvent(event);
844       }
845       else client->sendEvent(event);
846    }
847
848   }
849
850   /*!
851   \brief Send a message to create a variable group on server side
852   \param[in] id String identity of variable group that will be created on server
853   */
854   void CFile::sendAddVariableGroup(const string& id)
855   {
856    CContext* context = CContext::getCurrent();
857    if (! context->hasServer )
858    {
859       CContextClient* client = context->client;
860
861       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
862       if (client->isServerLeader())
863       {
864         CMessage msg;
865         msg << this->getId();
866         msg << id;
867         const std::list<int>& ranks = client->getRanksServerLeader();
868         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
869           event.push(*itRank,1,msg);
870         client->sendEvent(event);
871       }
872       else client->sendEvent(event);
873    }
874
875   }
876
877   /*!
878   \brief Receive a message annoucing the creation of a variable on server side
879   \param[in] event Received event
880   */
881   void CFile::recvAddVariable(CEventServer& event)
882   {
883
884      CBufferIn* buffer = event.subEvents.begin()->buffer;
885      string id;
886      *buffer>>id;
887      get(id)->recvAddVariable(*buffer);
888   }
889
890   /*!
891   \brief Receive a message annoucing the creation of a variable on server side
892   \param[in] buffer Buffer containing message
893   */
894   void CFile::recvAddVariable(CBufferIn& buffer)
895   {
896      string id;
897      buffer>>id;
898      addVariable(id);
899   }
900
901   /*!
902   \brief Receive a message annoucing the creation of a variable group on server side
903   \param[in] event Received event
904   */
905   void CFile::recvAddVariableGroup(CEventServer& event)
906   {
907
908      CBufferIn* buffer = event.subEvents.begin()->buffer;
909      string id;
910      *buffer>>id;
911      get(id)->recvAddVariableGroup(*buffer);
912   }
913
914   /*!
915   \brief Receive a message annoucing the creation of a variable group on server side
916   \param[in] buffer Buffer containing message
917   */
918   void CFile::recvAddVariableGroup(CBufferIn& buffer)
919   {
920      string id;
921      buffer>>id;
922      addVariableGroup(id);
923   }
924
925   /*!
926     \brief Sending all active (enabled) fields from client to server.
927   Each field is identified uniquely by its string identity. Not only should we
928   send the id to server but also we need to send ids of reference domain and reference axis.
929   With these two id, it's easier to make reference to grid where all data should be written.
930   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
931   */
932   void CFile::sendEnabledFields()
933   {
934     int size = this->enabledFields.size();
935     CField* fieldPtr(0);
936     for (int i = 0; i < size; ++i)
937     {
938       fieldPtr = this->enabledFields[i];
939       if (fieldPtr->name.isEmpty()) fieldPtr->name.setValue(fieldPtr->getBaseFieldReference()->getId());
940       this->sendAddField(fieldPtr->getId());
941       fieldPtr->sendAllAttributesToServer();
942       fieldPtr->sendAddAllVariables();
943     }
944   }
945
946   /*!
947   \brief Dispatch event received from client
948      Whenever a message is received in buffer of server, it will be processed depending on
949   its event type. A new event type should be added in the switch list to make sure
950   it processed on server side.
951   \param [in] event: Received message
952   */
953   bool CFile::dispatchEvent(CEventServer& event)
954   {
955      if (SuperClass::dispatchEvent(event)) return true;
956      else
957      {
958        switch(event.type)
959        {
960           case EVENT_ID_ADD_FIELD :
961             recvAddField(event);
962             return true;
963             break;
964
965           case EVENT_ID_ADD_FIELD_GROUP :
966             recvAddFieldGroup(event);
967             return true;
968             break;
969
970            case EVENT_ID_ADD_VARIABLE :
971             recvAddVariable(event);
972             return true;
973             break;
974
975           case EVENT_ID_ADD_VARIABLE_GROUP :
976             recvAddVariableGroup(event);
977             return true;
978             break;
979           default :
980              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
981           return false;
982        }
983      }
984   }
985
986
987
988
989   ///---------------------------------------------------------------
990
991} // namespace xios
Note: See TracBrowser for help on using the repository browser.