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

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

Add a new attribute to the file definition so that the output format can be controlled.

Currently the supported formats are "netcdf4" and "netcdf4_classic". The "format" attribute is optional. The "netcdf4" format will be used when no format is explicitly defined. Since "netcdf4" is the format which was previously used by XIOS, existing configuration files will not be affected by this change.

If "netcdf4_classic" is used, the output file(s) will be created using the classic NetCDF format. This format can be used with the attribute "type" set to "one_file" if the NetCDF4 library was compiled with Parallel NetCDF support (--enable-pnetcdf).

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