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

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

Reading for two-level server

+) Update reading with the changes of grid distribution
+) Correct a minor bug on modification grid mask
+) Do some code cleaning

Test
+) On Curie
+) Work in both mode: classical and two-level
+) Push some *.nc for test_remap

  • 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: 37.6 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     CContext* context = CContext::getCurrent();
619     // CContextClient* client=context->client;
620     CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[0] : context->client;
621
622     // It would probably be better to call initFile() somehow
623     // MPI_Comm_dup(client->intraComm, &fileComm);
624     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
625
626     checkReadFile();
627
628     for (int idx = 0; idx < enabledFields.size(); ++idx)
629     {
630        // First of all, find out which domain and axis associated with this field
631        enabledFields[idx]->solveGridReference();
632
633        // Read attributes of domain and axis from this file
634        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
635
636        // Now complete domain and axis associated with this field
637        enabledFields[idx]->solveGenerateGrid();
638
639        // Read necessary value from file
640        this->data_in->readFieldAttributesValues(enabledFields[idx]);
641
642        // Fill attributes for base reference
643        enabledFields[idx]->solveGridDomainAxisBaseRef();
644     }
645
646     // Now everything is ok, close it
647     close();
648   }
649
650
651   /*!
652   \brief Parse xml file and write information into file object
653   \param [in] node xmld node corresponding in xml file
654   */
655   void CFile::parse(xml::CXMLNode & node)
656   {
657      SuperClass::parse(node);
658
659      if (node.goToChildElement())
660      {
661        do
662        {
663           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
664           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
665        } while (node.goToNextElement());
666        node.goToParentElement();
667      }
668
669   }
670   //----------------------------------------------------------------
671
672   /*!
673   \brief Represent a file in form of string with all its info
674   \return String
675   */
676   StdString CFile::toString(void) const
677   {
678      StdOStringStream oss;
679
680      oss << "<" << CFile::GetName() << " ";
681      if (this->hasId())
682         oss << " id=\"" << this->getId() << "\" ";
683      oss << SuperClassAttribute::toString() << ">" << std::endl;
684      if (this->getVirtualFieldGroup() != NULL)
685         oss << *this->getVirtualFieldGroup() << std::endl;
686      oss << "</" << CFile::GetName() << " >";
687      return (oss.str());
688   }
689
690   //----------------------------------------------------------------
691
692   /*!
693   \brief Find all inheritace among objects in a file.
694   \param [in] apply (true) write attributes of parent into ones of child if they are empty
695                     (false) write attributes of parent into a new container of child
696   \param [in] parent
697   */
698   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
699   {
700      SuperClassAttribute::setAttributes(parent,apply);
701      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
702      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
703   }
704
705   //----------------------------------------------------------------
706
707   /*!
708   \brief Resolve all reference of active fields.
709      In order to know exactly which data each active field has, a search for all its
710   reference to find its parents or/and its base reference object must be done. Moreover
711   during this search, there are some information that can only be sent to server AFTER
712   all information of active fields are created on server side, e.g: checking mask or index
713   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
714   */
715   void CFile::solveOnlyRefOfEnabledFields(bool sendToServer)
716   {
717     int size = this->enabledFields.size();
718     for (int i = 0; i < size; ++i)
719     {
720       this->enabledFields[i]->solveOnlyReferenceEnabledField(sendToServer);
721       // this->enabledFields[i]->solveAllEnabledFields();
722//       this->enabledFields[i]->buildGridTransformationGraph();
723     }
724   }
725
726   void CFile::checkGridOfEnabledFields()
727   { 
728     int size = this->enabledFields.size();
729     for (int i = 0; i < size; ++i)
730     {
731       this->enabledFields[i]->checkGridOfEnabledFields();
732     }
733   }
734
735   void CFile::sendGridOfEnabledFields()
736   { 
737     int size = this->enabledFields.size();
738     for (int i = 0; i < size; ++i)
739     {
740       this->enabledFields[i]->sendGridOfEnabledFields();
741     }
742   }
743
744   void CFile::generateNewTransformationGridDest()
745   {
746     int size = this->enabledFields.size();
747     for (int i = 0; i < size; ++i)
748     {
749       this->enabledFields[i]->generateNewTransformationGridDest();
750     }
751   }
752
753   /*!
754   \brief Resolve all reference of active fields.
755      In order to know exactly which data each active field has, a search for all its
756   reference to find its parents or/and its base reference object must be done. Moreover
757   during this search, there are some information that can only be sent to server AFTER
758   all information of active fields are created on server side, e.g: checking mask or index
759   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
760   */
761   void CFile::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
762   {
763     int size = this->enabledFields.size();
764     for (int i = 0; i < size; ++i)
765     {
766       // this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
767      this->enabledFields[i]->solveAllEnabledFieldsAndTransform();
768     }
769   }
770
771   /*!
772    * Constructs the filter graph for each active field.
773    *
774    * \param gc the garbage collector to use when building the filter graph
775    */
776   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
777   {
778     int size = this->enabledFields.size();
779     for (int i = 0; i < size; ++i)
780     {
781       this->enabledFields[i]->buildFilterGraph(gc, true);
782     }
783   }
784
785   /*!
786     Prefetching the data for enabled fields read from file.
787   */
788   void CFile::prefetchEnabledReadModeFields(void)
789   {
790     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
791       return;
792
793     int size = this->enabledFields.size();
794     for (int i = 0; i < size; ++i)
795       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
796   }
797
798   /*!
799     Prefetching the data for enabled fields read from file whose data is out-of-date.
800   */
801   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
802   {
803     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
804       return;
805
806     int size = this->enabledFields.size();
807     for (int i = 0; i < size; ++i)
808       this->enabledFields[i]->sendReadDataRequestIfNeeded();
809   }
810
811   void CFile::solveFieldRefInheritance(bool apply)
812   {
813      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
814      std::vector<CField*> allF = this->getAllFields();
815      for (unsigned int i = 0; i < allF.size(); i++)
816         allF[i]->solveRefInheritance(apply);
817   }
818
819   //----------------------------------------------------------------
820
821   /*!
822   \brief Add a field into file.
823      A field is added into file and it will be written out if the file is enabled and
824   level of this field is smaller than level_output. A new field won't be created if one
825   with id has already existed
826   \param [in] id String identity of new field
827   \return Pointer to added (or already existed) field
828   */
829   CField* CFile::addField(const string& id)
830   {
831     return vFieldGroup->createChild(id);
832   }
833
834   /*!
835   \brief Add a field group into file.
836      A field group is added into file and it will play a role as parents for fields.
837   A new field group won't be created if one with id has already existed
838   \param [in] id String identity of new field group
839   \return Pointer to added (or already existed) field group
840   */
841   CFieldGroup* CFile::addFieldGroup(const string& id)
842   {
843     return vFieldGroup->createChildGroup(id);
844   }
845
846   /*!
847   \brief Add a variable into file.
848      A variable is added into file and if one with id has already existed, pointer to
849   it will be returned.
850      Variable as long as attributes are information container of file.
851   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
852   to fill in (extra) information for a file.
853   \param [in] id String identity of new variable
854   \return Pointer to added (or already existed) variable
855   */
856   CVariable* CFile::addVariable(const string& id)
857   {
858     return vVariableGroup->createChild(id);
859   }
860
861   /*!
862   \brief Add a variable group into file.
863      A variable group is added into file and it will play a role as parents for variables.
864   A new variable group won't be created if one with id has already existed
865   \param [in] id String identity of new variable group
866   \return Pointer to added (or already existed) variable group
867   */
868   CVariableGroup* CFile::addVariableGroup(const string& id)
869   {
870     return vVariableGroup->createChildGroup(id);
871   }
872
873   void CFile::setContextClient(CContextClient* newContextClient)
874   {
875     client = newContextClient;
876   }
877
878   CContextClient* CFile::getContextClient()
879   {
880     return client;
881   }
882
883
884   /*!
885   \brief Send a message to create a field on server side
886   \param[in] id String identity of field that will be created on server
887   */
888   void CFile::sendAddField(const string& id)
889   {
890      sendAddItem(id, EVENT_ID_ADD_FIELD);
891   }
892
893   void CFile::sendAddField(const string& id, CContextClient* client)
894   {
895      sendAddItem(id, EVENT_ID_ADD_FIELD, client);
896   }
897
898   /*!
899   \brief Send a message to create a field group on server side
900   \param[in] id String identity of field group that will be created on server
901   */
902   void CFile::sendAddFieldGroup(const string& id)
903   {
904      sendAddItem(id, (int)EVENT_ID_ADD_FIELD_GROUP);
905   }
906
907   /*!
908   \brief Send a message to create a field group on server side
909   \param[in] id String identity of field group that will be created on server
910   */
911   void CFile::sendAddFieldGroup(const string& id, CContextClient* client)
912   {
913      sendAddItem(id, (int)EVENT_ID_ADD_FIELD_GROUP, client);
914   }
915
916   /*!
917   \brief Receive a message annoucing the creation of a field on server side
918   \param[in] event Received event
919   */
920   void CFile::recvAddField(CEventServer& event)
921   {
922
923      CBufferIn* buffer = event.subEvents.begin()->buffer;
924      string id;
925      *buffer>>id;
926      get(id)->recvAddField(*buffer);
927   }
928
929   /*!
930   \brief Receive a message annoucing the creation of a field on server side
931   \param[in] buffer Buffer containing message
932   */
933   void CFile::recvAddField(CBufferIn& buffer)
934   {
935      string id;
936      buffer>>id;
937      addField(id);
938   }
939
940   /*!
941   \brief Receive a message annoucing the creation of a field group on server side
942   \param[in] event Received event
943   */
944   void CFile::recvAddFieldGroup(CEventServer& event)
945   {
946
947      CBufferIn* buffer = event.subEvents.begin()->buffer;
948      string id;
949      *buffer>>id;
950      get(id)->recvAddFieldGroup(*buffer);
951   }
952
953   /*!
954   \brief Receive a message annoucing the creation of a field group on server side
955   \param[in] buffer Buffer containing message
956   */
957   void CFile::recvAddFieldGroup(CBufferIn& buffer)
958   {
959      string id;
960      buffer>>id;
961      addFieldGroup(id);
962   }
963
964   /*!
965   \brief Send messages to duplicate all variables on server side
966      Because each variable has also its attributes. So first thing to do is replicate
967   all these attributes on server side. Because variable can have a value, the second thing
968   is to duplicate this value on server, too.
969   */
970   void CFile::sendAddAllVariables()
971   {
972     std::vector<CVariable*> allVar = getAllVariables();
973     std::vector<CVariable*>::const_iterator it = allVar.begin();
974     std::vector<CVariable*>::const_iterator itE = allVar.end();
975
976     for (; it != itE; ++it)
977     {
978       this->sendAddVariable((*it)->getId());
979       (*it)->sendAllAttributesToServer();
980       (*it)->sendValue();
981     }
982   }
983
984   void CFile::sendAddAllVariables(CContextClient* client)
985   {
986     std::vector<CVariable*> allVar = getAllVariables();
987     std::vector<CVariable*>::const_iterator it = allVar.begin();
988     std::vector<CVariable*>::const_iterator itE = allVar.end();
989
990     for (; it != itE; ++it)
991     {
992       this->sendAddVariable((*it)->getId(), client);
993       (*it)->sendAllAttributesToServer(client);
994       (*it)->sendValue(client);
995     }
996   }
997
998   /*!
999   \brief Send a message to create a variable group on server side
1000   \param[in] id String identity of variable group that will be created on server
1001   */
1002   void CFile::sendAddVariableGroup(const string& id)
1003   {
1004      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP);
1005   }
1006
1007   /*!
1008   \brief Send a message to create a variable group on server side
1009   \param[in] id String identity of variable group that will be created on server
1010   \param [in] client client to which we will send this adding action
1011   */
1012   void CFile::sendAddVariableGroup(const string& id, CContextClient* client)
1013   {
1014      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1015   }
1016
1017   /*!
1018   \brief Send a message to create a variable on server side
1019      A variable always belongs to a variable group
1020   \param[in] id String identity of variable that will be created on server
1021   */
1022   void CFile::sendAddVariable(const string& id)
1023   {
1024      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE);
1025   }
1026
1027   /*
1028     Send message to add a variable into a file within a certain client
1029     \param [in] id String identity of a variable
1030     \param [in] client client to which we will send this adding action
1031   */
1032   void CFile::sendAddVariable(const string& id, CContextClient* client)
1033   {
1034      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1035   }
1036
1037   /*!
1038   \brief Receive a message annoucing the creation of a variable on server side
1039   \param[in] event Received event
1040   */
1041   void CFile::recvAddVariable(CEventServer& event)
1042   {
1043
1044      CBufferIn* buffer = event.subEvents.begin()->buffer;
1045      string id;
1046      *buffer>>id;
1047      get(id)->recvAddVariable(*buffer);
1048   }
1049
1050   /*!
1051   \brief Receive a message annoucing the creation of a variable on server side
1052   \param[in] buffer Buffer containing message
1053   */
1054   void CFile::recvAddVariable(CBufferIn& buffer)
1055   {
1056      string id;
1057      buffer>>id;
1058      addVariable(id);
1059   }
1060
1061   /*!
1062   \brief Receive a message annoucing the creation of a variable group on server side
1063   \param[in] event Received event
1064   */
1065   void CFile::recvAddVariableGroup(CEventServer& event)
1066   {
1067
1068      CBufferIn* buffer = event.subEvents.begin()->buffer;
1069      string id;
1070      *buffer>>id;
1071      get(id)->recvAddVariableGroup(*buffer);
1072   }
1073
1074   /*!
1075   \brief Receive a message annoucing the creation of a variable group on server side
1076   \param[in] buffer Buffer containing message
1077   */
1078   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1079   {
1080      string id;
1081      buffer>>id;
1082      addVariableGroup(id);
1083   }
1084
1085   /*!
1086     \brief Sending all active (enabled) fields from client to server.
1087   Each field is identified uniquely by its string identity. Not only should we
1088   send the id to server but also we need to send ids of reference domain and reference axis.
1089   With these two id, it's easier to make reference to grid where all data should be written.
1090   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1091   */
1092   void CFile::sendEnabledFields(CContextClient* client)
1093   {
1094     size_t size = this->enabledFields.size();
1095     for (size_t i = 0; i < size; ++i)
1096     {
1097       CField* field = this->enabledFields[i];
1098       this->sendAddField(field->getId(), client);
1099       field->sendAllAttributesToServer(client);
1100       field->sendAddAllVariables(client);
1101     }
1102   }
1103
1104
1105   /*!
1106   \brief Dispatch event received from client
1107      Whenever a message is received in buffer of server, it will be processed depending on
1108   its event type. A new event type should be added in the switch list to make sure
1109   it processed on server side.
1110   \param [in] event: Received message
1111   */
1112   bool CFile::dispatchEvent(CEventServer& event)
1113   {
1114      if (SuperClass::dispatchEvent(event)) return true;
1115      else
1116      {
1117        switch(event.type)
1118        {
1119           case EVENT_ID_ADD_FIELD :
1120             recvAddField(event);
1121             return true;
1122             break;
1123
1124           case EVENT_ID_ADD_FIELD_GROUP :
1125             recvAddFieldGroup(event);
1126             return true;
1127             break;
1128
1129            case EVENT_ID_ADD_VARIABLE :
1130             recvAddVariable(event);
1131             return true;
1132             break;
1133
1134           case EVENT_ID_ADD_VARIABLE_GROUP :
1135             recvAddVariableGroup(event);
1136             return true;
1137             break;
1138           default :
1139              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1140           return false;
1141        }
1142      }
1143   }
1144
1145
1146
1147
1148   ///---------------------------------------------------------------
1149
1150} // namespace xios
Note: See TracBrowser for help on using the repository browser.