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

Last change on this file since 770 was 770, checked in by rlacroix, 6 years ago

Field: Handle more correctly the output name for the fields with a field_ref.

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