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

Last change on this file since 771 was 771, checked in by rlacroix, 8 years ago

Remove the now unused base reference framework.

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