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

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

Add a new file attribute time_counter_name.

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