source: XIOS/dev/dev_olga/src/node/file.cpp @ 1158

Last change on this file since 1158 was 1158, checked in by oabramkina, 7 years ago

Two server levels: merging with trunk r1137.
There are bugs.

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