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

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

Allow using more servers than clients.

This will be useful later when implementing server to client communications.

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