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

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

Field: Avoid some heap allocations.

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