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

Last change on this file since 1144 was 1144, checked in by mhnguyen, 7 years ago

Cleaning up some redundant codes

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