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

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

Add the infrastructure to request fields from the server.

This will be used to read input files so add a new file attribute mode to define whether data is written or read from a file.

Currently the data is not actually read and random data is transfered for those fields in read mode.

  • 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.7 KB
Line 
1#include "file.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "object_factory.hpp"
7#include "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   /*!
520     Prefetching the data for enabled fields read from file.
521   */
522   void CFile::prefetchEnabledReadModeFields(void)
523   {
524     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
525       return;
526
527     int size = this->enabledFields.size();
528     for (int i = 0; i < size; ++i)
529       this->enabledFields[i]->sendReadDataRequest();
530   }
531
532   /*!
533     Prefetching the data for enabled fields read from file whose data is out-of-date.
534   */
535   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
536   {
537     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
538       return;
539
540     int size = this->enabledFields.size();
541     for (int i = 0; i < size; ++i)
542       this->enabledFields[i]->sendReadDataRequestIfNeeded();
543   }
544
545   void CFile::solveFieldRefInheritance(bool apply)
546   {
547      // Résolution des héritages par référence de chacun des champs contenus dans le fichier.
548      std::vector<CField*> allF = this->getAllFields();
549      for (unsigned int i = 0; i < allF.size(); i++)
550         allF[i]->solveRefInheritance(apply);
551   }
552
553   //----------------------------------------------------------------
554
555   void CFile::solveEFGridRef(void)
556   {
557      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
558         this->enabledFields[i]->solveGridReference();
559   }
560
561   //----------------------------------------------------------------
562
563   void CFile::solveEFOperation(void)
564   {
565      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
566         this->enabledFields[i]->solveOperation();
567   }
568
569   void CFile::solveEFExpression(void)
570   {
571      for (unsigned int i = 0; i < this->enabledFields.size(); i++)
572         this->enabledFields[i]->buildExpression();
573   }
574
575   /*!
576   \brief Add a field into file.
577      A field is added into file and it will be written out if the file is enabled and
578   level of this field is smaller than level_output. A new field won't be created if one
579   with id has already existed
580   \param [in] id String identity of new field
581   \return Pointer to added (or already existed) field
582   */
583   CField* CFile::addField(const string& id)
584   {
585     return vFieldGroup->createChild(id) ;
586   }
587
588   /*!
589   \brief Add a field group into file.
590      A field group is added into file and it will play a role as parents for fields.
591   A new field group won't be created if one with id has already existed
592   \param [in] id String identity of new field group
593   \return Pointer to added (or already existed) field group
594   */
595   CFieldGroup* CFile::addFieldGroup(const string& id)
596   {
597     return vFieldGroup->createChildGroup(id) ;
598   }
599
600   /*!
601   \brief Add a variable into file.
602      A variable is added into file and if one with id has already existed, pointer to
603   it will be returned.
604      Variable as long as attributes are information container of file.
605   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
606   to fill in (extra) information for a file.
607   \param [in] id String identity of new variable
608   \return Pointer to added (or already existed) variable
609   */
610   CVariable* CFile::addVariable(const string& id)
611   {
612     return vVariableGroup->createChild(id) ;
613   }
614
615   /*!
616   \brief Add a variable group into file.
617      A variable group is added into file and it will play a role as parents for variables.
618   A new variable group won't be created if one with id has already existed
619   \param [in] id String identity of new variable group
620   \return Pointer to added (or already existed) variable group
621   */
622   CVariableGroup* CFile::addVariableGroup(const string& id)
623   {
624     return vVariableGroup->createChildGroup(id) ;
625   }
626
627   /*!
628   \brief Send a message to create a field on server side
629   \param[in] id String identity of field that will be created on server
630   */
631   void CFile::sendAddField(const string& id)
632   {
633    CContext* context=CContext::getCurrent() ;
634
635    if (! context->hasServer )
636    {
637       CContextClient* client=context->client ;
638
639       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD) ;
640       if (client->isServerLeader())
641       {
642         CMessage msg ;
643         msg<<this->getId() ;
644         msg<<id ;
645         const std::list<int>& ranks = client->getRanksServerLeader();
646         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
647           event.push(*itRank,1,msg);
648         client->sendEvent(event) ;
649       }
650       else client->sendEvent(event) ;
651    }
652
653   }
654
655   /*!
656   \brief Send a message to create a field group on server side
657   \param[in] id String identity of field group that will be created on server
658   */
659   void CFile::sendAddFieldGroup(const string& id)
660   {
661    CContext* context=CContext::getCurrent() ;
662    if (! context->hasServer )
663    {
664       CContextClient* client=context->client ;
665
666       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP) ;
667       if (client->isServerLeader())
668       {
669         CMessage msg ;
670         msg<<this->getId() ;
671         msg<<id ;
672         const std::list<int>& ranks = client->getRanksServerLeader();
673         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
674           event.push(*itRank,1,msg);
675         client->sendEvent(event) ;
676       }
677       else client->sendEvent(event) ;
678    }
679
680   }
681
682   /*!
683   \brief Receive a message annoucing the creation of a field on server side
684   \param[in] event Received event
685   */
686   void CFile::recvAddField(CEventServer& event)
687   {
688
689      CBufferIn* buffer=event.subEvents.begin()->buffer;
690      string id;
691      *buffer>>id ;
692      get(id)->recvAddField(*buffer) ;
693   }
694
695   /*!
696   \brief Receive a message annoucing the creation of a field on server side
697   \param[in] buffer Buffer containing message
698   */
699   void CFile::recvAddField(CBufferIn& buffer)
700   {
701      string id ;
702      buffer>>id ;
703      addField(id) ;
704   }
705
706   /*!
707   \brief Receive a message annoucing the creation of a field group on server side
708   \param[in] event Received event
709   */
710   void CFile::recvAddFieldGroup(CEventServer& event)
711   {
712
713      CBufferIn* buffer=event.subEvents.begin()->buffer;
714      string id;
715      *buffer>>id ;
716      get(id)->recvAddFieldGroup(*buffer) ;
717   }
718
719   /*!
720   \brief Receive a message annoucing the creation of a field group on server side
721   \param[in] buffer Buffer containing message
722   */
723   void CFile::recvAddFieldGroup(CBufferIn& buffer)
724   {
725      string id ;
726      buffer>>id ;
727      addFieldGroup(id) ;
728   }
729
730   /*!
731   \brief Send messages to duplicate all variables on server side
732      Because each variable has also its attributes. So first thing to do is replicate
733   all these attributes on server side. Because variable can have a value, the second thing
734   is to duplicate this value on server, too.
735   */
736   void CFile::sendAddAllVariables()
737   {
738     if (!getAllVariables().empty())
739     {
740       // Firstly, it's necessary to add virtual variable group
741       sendAddVariableGroup(getVirtualVariableGroup()->getId());
742
743       // Okie, now we can add to this variable group
744       std::vector<CVariable*> allVar = getAllVariables();
745       std::vector<CVariable*>::const_iterator it = allVar.begin();
746       std::vector<CVariable*>::const_iterator itE = allVar.end();
747
748       for (; it != itE; ++it)
749       {
750         this->sendAddVariable((*it)->getId());
751         (*it)->sendAllAttributesToServer();
752         (*it)->sendValue();
753       }
754     }
755   }
756
757   /*!
758   \brief Send a message to create a variable on server side
759      A variable always belongs to a variable group
760   \param[in] id String identity of variable that will be created on server
761   */
762   void CFile::sendAddVariable(const string& id)
763   {
764    CContext* context=CContext::getCurrent() ;
765
766    if (! context->hasServer )
767    {
768       CContextClient* client=context->client ;
769
770       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE) ;
771       if (client->isServerLeader())
772       {
773         CMessage msg ;
774         msg<<this->getId() ;
775         msg<<id ;
776         const std::list<int>& ranks = client->getRanksServerLeader();
777         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
778           event.push(*itRank,1,msg);
779         client->sendEvent(event) ;
780       }
781       else client->sendEvent(event) ;
782    }
783
784   }
785
786   /*!
787   \brief Send a message to create a variable group on server side
788   \param[in] id String identity of variable group that will be created on server
789   */
790   void CFile::sendAddVariableGroup(const string& id)
791   {
792    CContext* context=CContext::getCurrent() ;
793    if (! context->hasServer )
794    {
795       CContextClient* client=context->client ;
796
797       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP) ;
798       if (client->isServerLeader())
799       {
800         CMessage msg ;
801         msg<<this->getId() ;
802         msg<<id ;
803         const std::list<int>& ranks = client->getRanksServerLeader();
804         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
805           event.push(*itRank,1,msg);
806         client->sendEvent(event) ;
807       }
808       else client->sendEvent(event) ;
809    }
810
811   }
812
813   /*!
814   \brief Receive a message annoucing the creation of a variable on server side
815   \param[in] event Received event
816   */
817   void CFile::recvAddVariable(CEventServer& event)
818   {
819
820      CBufferIn* buffer=event.subEvents.begin()->buffer;
821      string id;
822      *buffer>>id ;
823      get(id)->recvAddVariable(*buffer) ;
824   }
825
826   /*!
827   \brief Receive a message annoucing the creation of a variable on server side
828   \param[in] buffer Buffer containing message
829   */
830   void CFile::recvAddVariable(CBufferIn& buffer)
831   {
832      string id ;
833      buffer>>id ;
834      addVariable(id) ;
835   }
836
837   /*!
838   \brief Receive a message annoucing the creation of a variable group on server side
839   \param[in] event Received event
840   */
841   void CFile::recvAddVariableGroup(CEventServer& event)
842   {
843
844      CBufferIn* buffer=event.subEvents.begin()->buffer;
845      string id;
846      *buffer>>id ;
847      get(id)->recvAddVariableGroup(*buffer) ;
848   }
849
850   /*!
851   \brief Receive a message annoucing the creation of a variable group on server side
852   \param[in] buffer Buffer containing message
853   */
854   void CFile::recvAddVariableGroup(CBufferIn& buffer)
855   {
856      string id ;
857      buffer>>id ;
858      addVariableGroup(id) ;
859   }
860
861   /*!
862     \brief Sending all active (enabled) fields from client to server.
863   Each field is identified uniquely by its string identity. Not only should we
864   send the id to server but also we need to send ids of reference domain and reference axis.
865   With these two id, it's easier to make reference to grid where all data should be written.
866   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
867   */
868   void CFile::sendEnabledFields()
869   {
870     int size = this->enabledFields.size();
871     CField* fieldPtr(0);
872     for (int i = 0; i < size; ++i)
873     {
874       fieldPtr = this->enabledFields[i];
875       if (fieldPtr->name.isEmpty()) fieldPtr->name.setValue(fieldPtr->getBaseFieldReference()->getId());
876       this->sendAddField(fieldPtr->getId());
877       fieldPtr->sendAllAttributesToServer();
878       fieldPtr->sendAddAllVariables();
879     }
880   }
881
882   /*!
883   \brief Dispatch event received from client
884      Whenever a message is received in buffer of server, it will be processed depending on
885   its event type. A new event type should be added in the switch list to make sure
886   it processed on server side.
887   \param [in] event: Received message
888   */
889   bool CFile::dispatchEvent(CEventServer& event)
890   {
891      if (SuperClass::dispatchEvent(event)) return true ;
892      else
893      {
894        switch(event.type)
895        {
896           case EVENT_ID_ADD_FIELD :
897             recvAddField(event) ;
898             return true ;
899             break ;
900
901           case EVENT_ID_ADD_FIELD_GROUP :
902             recvAddFieldGroup(event) ;
903             return true ;
904             break ;
905
906            case EVENT_ID_ADD_VARIABLE :
907             recvAddVariable(event) ;
908             return true ;
909             break ;
910
911           case EVENT_ID_ADD_VARIABLE_GROUP :
912             recvAddVariableGroup(event) ;
913             return true ;
914             break ;
915           default :
916              ERROR("bool CFile::dispatchEvent(CEventServer& event)", <<"Unknown Event") ;
917           return false ;
918        }
919      }
920   }
921
922
923
924
925   ///---------------------------------------------------------------
926
927} // namespace xios
Note: See TracBrowser for help on using the repository browser.