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

Last change on this file since 811 was 811, checked in by ymipsl, 8 years ago

Bug fix when time dimension is not the unlimited dimension

YM

  • 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: 34.0 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      if (time_counter_name.isEmpty()) data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective));
528      else 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     // It would probably be better to call initFile() somehow
557     MPI_Comm_dup(client->intraComm, &fileComm);
558     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
559
560     checkFile();
561
562     for (int idx = 0; idx < enabledFields.size(); ++idx)
563     {
564        // First of all, find out which domain and axis associated with this field
565        enabledFields[idx]->solveGridReference();
566
567        // Read attributes of domain and axis from this file
568        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
569
570        // Now complete domain and axis associated with this field
571        enabledFields[idx]->solveGenerateGrid();
572
573        // Read necessary value from file
574        this->data_in->readFieldAttributesValues(enabledFields[idx]);
575
576        // Fill attributes for base reference
577        enabledFields[idx]->solveGridDomainAxisBaseRef();
578     }
579
580     // Now everything is ok, close it
581     close();
582   }
583
584
585   /*!
586   \brief Parse xml file and write information into file object
587   \param [in] node xmld node corresponding in xml file
588   */
589   void CFile::parse(xml::CXMLNode & node)
590   {
591      SuperClass::parse(node);
592
593      if (node.goToChildElement())
594      {
595        do
596        {
597           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
598           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
599        } while (node.goToNextElement());
600        node.goToParentElement();
601      }
602
603   }
604   //----------------------------------------------------------------
605
606   /*!
607   \brief Represent a file in form of string with all its info
608   \return String
609   */
610   StdString CFile::toString(void) const
611   {
612      StdOStringStream oss;
613
614      oss << "<" << CFile::GetName() << " ";
615      if (this->hasId())
616         oss << " id=\"" << this->getId() << "\" ";
617      oss << SuperClassAttribute::toString() << ">" << std::endl;
618      if (this->getVirtualFieldGroup() != NULL)
619         oss << *this->getVirtualFieldGroup() << std::endl;
620      oss << "</" << CFile::GetName() << " >";
621      return (oss.str());
622   }
623
624   //----------------------------------------------------------------
625
626   /*!
627   \brief Find all inheritace among objects in a file.
628   \param [in] apply (true) write attributes of parent into ones of child if they are empty
629                     (false) write attributes of parent into a new container of child
630   \param [in] parent
631   */
632   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
633   {
634      SuperClassAttribute::setAttributes(parent,apply);
635      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
636      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
637   }
638
639   //----------------------------------------------------------------
640
641   /*!
642   \brief Resolve all reference of active fields.
643      In order to know exactly which data each active field has, a search for all its
644   reference to find its parents or/and its base reference object must be done. Moreover
645   during this search, there are some information that can only be sent to server AFTER
646   all information of active fields are created on server side, e.g: checking mask or index
647   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
648   */
649   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
650   {
651     int size = this->enabledFields.size();
652     for (int i = 0; i < size; ++i)
653     {
654       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
655     }
656   }
657
658   /*!
659    * Constructs the filter graph for each active field.
660    *
661    * \param gc the garbage collector to use when building the filter graph
662    */
663   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
664   {
665     int size = this->enabledFields.size();
666     for (int i = 0; i < size; ++i)
667     {
668       this->enabledFields[i]->buildFilterGraph(gc, true);
669     }
670   }
671
672   /*!
673     Prefetching the data for enabled fields read from file.
674   */
675   void CFile::prefetchEnabledReadModeFields(void)
676   {
677     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
678       return;
679
680     int size = this->enabledFields.size();
681     for (int i = 0; i < size; ++i)
682       this->enabledFields[i]->sendReadDataRequest();
683   }
684
685   /*!
686     Prefetching the data for enabled fields read from file whose data is out-of-date.
687   */
688   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
689   {
690     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
691       return;
692
693     int size = this->enabledFields.size();
694     for (int i = 0; i < size; ++i)
695       this->enabledFields[i]->sendReadDataRequestIfNeeded();
696   }
697
698   void CFile::solveFieldRefInheritance(bool apply)
699   {
700      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
701      std::vector<CField*> allF = this->getAllFields();
702      for (unsigned int i = 0; i < allF.size(); i++)
703         allF[i]->solveRefInheritance(apply);
704   }
705
706   //----------------------------------------------------------------
707
708   /*!
709   \brief Add a field into file.
710      A field is added into file and it will be written out if the file is enabled and
711   level of this field is smaller than level_output. A new field won't be created if one
712   with id has already existed
713   \param [in] id String identity of new field
714   \return Pointer to added (or already existed) field
715   */
716   CField* CFile::addField(const string& id)
717   {
718     return vFieldGroup->createChild(id);
719   }
720
721   /*!
722   \brief Add a field group into file.
723      A field group is added into file and it will play a role as parents for fields.
724   A new field group won't be created if one with id has already existed
725   \param [in] id String identity of new field group
726   \return Pointer to added (or already existed) field group
727   */
728   CFieldGroup* CFile::addFieldGroup(const string& id)
729   {
730     return vFieldGroup->createChildGroup(id);
731   }
732
733   /*!
734   \brief Add a variable into file.
735      A variable is added into file and if one with id has already existed, pointer to
736   it will be returned.
737      Variable as long as attributes are information container of file.
738   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
739   to fill in (extra) information for a file.
740   \param [in] id String identity of new variable
741   \return Pointer to added (or already existed) variable
742   */
743   CVariable* CFile::addVariable(const string& id)
744   {
745     return vVariableGroup->createChild(id);
746   }
747
748   /*!
749   \brief Add a variable group into file.
750      A variable group is added into file and it will play a role as parents for variables.
751   A new variable group won't be created if one with id has already existed
752   \param [in] id String identity of new variable group
753   \return Pointer to added (or already existed) variable group
754   */
755   CVariableGroup* CFile::addVariableGroup(const string& id)
756   {
757     return vVariableGroup->createChildGroup(id);
758   }
759
760   /*!
761   \brief Send a message to create a field on server side
762   \param[in] id String identity of field that will be created on server
763   */
764   void CFile::sendAddField(const string& id)
765   {
766    CContext* context = CContext::getCurrent();
767
768    if (! context->hasServer )
769    {
770       CContextClient* client = context->client;
771
772       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
773       if (client->isServerLeader())
774       {
775         CMessage msg;
776         msg << this->getId();
777         msg << id;
778         const std::list<int>& ranks = client->getRanksServerLeader();
779         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
780           event.push(*itRank,1,msg);
781         client->sendEvent(event);
782       }
783       else client->sendEvent(event);
784    }
785
786   }
787
788   /*!
789   \brief Send a message to create a field group on server side
790   \param[in] id String identity of field group that will be created on server
791   */
792   void CFile::sendAddFieldGroup(const string& id)
793   {
794    CContext* context = CContext::getCurrent();
795    if (! context->hasServer )
796    {
797       CContextClient* client = context->client;
798
799       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
800       if (client->isServerLeader())
801       {
802         CMessage msg;
803         msg << this->getId();
804         msg << id;
805         const std::list<int>& ranks = client->getRanksServerLeader();
806         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
807           event.push(*itRank,1,msg);
808         client->sendEvent(event);
809       }
810       else client->sendEvent(event);
811    }
812
813   }
814
815   /*!
816   \brief Receive a message annoucing the creation of a field on server side
817   \param[in] event Received event
818   */
819   void CFile::recvAddField(CEventServer& event)
820   {
821
822      CBufferIn* buffer = event.subEvents.begin()->buffer;
823      string id;
824      *buffer>>id;
825      get(id)->recvAddField(*buffer);
826   }
827
828   /*!
829   \brief Receive a message annoucing the creation of a field on server side
830   \param[in] buffer Buffer containing message
831   */
832   void CFile::recvAddField(CBufferIn& buffer)
833   {
834      string id;
835      buffer>>id;
836      addField(id);
837   }
838
839   /*!
840   \brief Receive a message annoucing the creation of a field group on server side
841   \param[in] event Received event
842   */
843   void CFile::recvAddFieldGroup(CEventServer& event)
844   {
845
846      CBufferIn* buffer = event.subEvents.begin()->buffer;
847      string id;
848      *buffer>>id;
849      get(id)->recvAddFieldGroup(*buffer);
850   }
851
852   /*!
853   \brief Receive a message annoucing the creation of a field group on server side
854   \param[in] buffer Buffer containing message
855   */
856   void CFile::recvAddFieldGroup(CBufferIn& buffer)
857   {
858      string id;
859      buffer>>id;
860      addFieldGroup(id);
861   }
862
863   /*!
864   \brief Send messages to duplicate all variables on server side
865      Because each variable has also its attributes. So first thing to do is replicate
866   all these attributes on server side. Because variable can have a value, the second thing
867   is to duplicate this value on server, too.
868   */
869   void CFile::sendAddAllVariables()
870   {
871     if (!getAllVariables().empty())
872     {
873       // Firstly, it's necessary to add virtual variable group
874       sendAddVariableGroup(getVirtualVariableGroup()->getId());
875
876       // Okie, now we can add to this variable group
877       std::vector<CVariable*> allVar = getAllVariables();
878       std::vector<CVariable*>::const_iterator it = allVar.begin();
879       std::vector<CVariable*>::const_iterator itE = allVar.end();
880
881       for (; it != itE; ++it)
882       {
883         this->sendAddVariable((*it)->getId());
884         (*it)->sendAllAttributesToServer();
885         (*it)->sendValue();
886       }
887     }
888   }
889
890   /*!
891   \brief Send a message to create a variable on server side
892      A variable always belongs to a variable group
893   \param[in] id String identity of variable that will be created on server
894   */
895   void CFile::sendAddVariable(const string& id)
896   {
897    CContext* context = CContext::getCurrent();
898
899    if (! context->hasServer )
900    {
901       CContextClient* client = context->client;
902
903       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
904       if (client->isServerLeader())
905       {
906         CMessage msg;
907         msg << this->getId();
908         msg << id;
909         const std::list<int>& ranks = client->getRanksServerLeader();
910         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
911           event.push(*itRank,1,msg);
912         client->sendEvent(event);
913       }
914       else client->sendEvent(event);
915    }
916
917   }
918
919   /*!
920   \brief Send a message to create a variable group on server side
921   \param[in] id String identity of variable group that will be created on server
922   */
923   void CFile::sendAddVariableGroup(const string& id)
924   {
925    CContext* context = CContext::getCurrent();
926    if (! context->hasServer )
927    {
928       CContextClient* client = context->client;
929
930       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
931       if (client->isServerLeader())
932       {
933         CMessage msg;
934         msg << this->getId();
935         msg << id;
936         const std::list<int>& ranks = client->getRanksServerLeader();
937         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
938           event.push(*itRank,1,msg);
939         client->sendEvent(event);
940       }
941       else client->sendEvent(event);
942    }
943
944   }
945
946   /*!
947   \brief Receive a message annoucing the creation of a variable on server side
948   \param[in] event Received event
949   */
950   void CFile::recvAddVariable(CEventServer& event)
951   {
952
953      CBufferIn* buffer = event.subEvents.begin()->buffer;
954      string id;
955      *buffer>>id;
956      get(id)->recvAddVariable(*buffer);
957   }
958
959   /*!
960   \brief Receive a message annoucing the creation of a variable on server side
961   \param[in] buffer Buffer containing message
962   */
963   void CFile::recvAddVariable(CBufferIn& buffer)
964   {
965      string id;
966      buffer>>id;
967      addVariable(id);
968   }
969
970   /*!
971   \brief Receive a message annoucing the creation of a variable group on server side
972   \param[in] event Received event
973   */
974   void CFile::recvAddVariableGroup(CEventServer& event)
975   {
976
977      CBufferIn* buffer = event.subEvents.begin()->buffer;
978      string id;
979      *buffer>>id;
980      get(id)->recvAddVariableGroup(*buffer);
981   }
982
983   /*!
984   \brief Receive a message annoucing the creation of a variable group on server side
985   \param[in] buffer Buffer containing message
986   */
987   void CFile::recvAddVariableGroup(CBufferIn& buffer)
988   {
989      string id;
990      buffer>>id;
991      addVariableGroup(id);
992   }
993
994   /*!
995     \brief Sending all active (enabled) fields from client to server.
996   Each field is identified uniquely by its string identity. Not only should we
997   send the id to server but also we need to send ids of reference domain and reference axis.
998   With these two id, it's easier to make reference to grid where all data should be written.
999   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1000   */
1001   void CFile::sendEnabledFields()
1002   {
1003     size_t size = this->enabledFields.size();
1004     for (size_t i = 0; i < size; ++i)
1005     {
1006       CField* field = this->enabledFields[i];
1007       this->sendAddField(field->getId());
1008       field->sendAllAttributesToServer();
1009       field->sendAddAllVariables();
1010     }
1011   }
1012
1013   /*!
1014   \brief Dispatch event received from client
1015      Whenever a message is received in buffer of server, it will be processed depending on
1016   its event type. A new event type should be added in the switch list to make sure
1017   it processed on server side.
1018   \param [in] event: Received message
1019   */
1020   bool CFile::dispatchEvent(CEventServer& event)
1021   {
1022      if (SuperClass::dispatchEvent(event)) return true;
1023      else
1024      {
1025        switch(event.type)
1026        {
1027           case EVENT_ID_ADD_FIELD :
1028             recvAddField(event);
1029             return true;
1030             break;
1031
1032           case EVENT_ID_ADD_FIELD_GROUP :
1033             recvAddFieldGroup(event);
1034             return true;
1035             break;
1036
1037            case EVENT_ID_ADD_VARIABLE :
1038             recvAddVariable(event);
1039             return true;
1040             break;
1041
1042           case EVENT_ID_ADD_VARIABLE_GROUP :
1043             recvAddVariableGroup(event);
1044             return true;
1045             break;
1046           default :
1047              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1048           return false;
1049        }
1050      }
1051   }
1052
1053
1054
1055
1056   ///---------------------------------------------------------------
1057
1058} // namespace xios
Note: See TracBrowser for help on using the repository browser.