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

Last change on this file since 773 was 773, checked in by rlacroix, 5 years ago

File/Variable?: Add an helper function to get the output name.

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