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

Last change on this file since 775 was 775, checked in by mhnguyen, 8 years ago

Implementing the reading of attributes of an axis from a file

+) 3d grid can be read directly from a file
+) Clean some redundant codes
+) Add new attribute declaration that allows to output only desired attributes

Test
+) On Curie
+) test_remap passes and result is correct

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