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

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

Allow restarting a simulation in append mode with file splitting enabled.

Make use of the new registry to save the start and end dates of the last output file.

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