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

Last change on this file since 1135 was 1135, checked in by ymipsl, 7 years ago
  • Add new timer for better profiling. The full timer output will be provided only for info_level=100
  • Add new file attribute : convention_str (string) : this string will overide the default value wrote in the file (CF-1.6 or UGRID)

YM

  • 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.2 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<CAxis*> setAxis;
240      // set<CDomain*> setDomains;
241      set<StdString> setAxis;
242      set<StdString> setDomains;
243     
244      std::vector<CField*>::iterator it, end = this->enabledFields.end();
245      for (it = this->enabledFields.begin(); it != end; it++)
246      {
247         CField* field = *it;
248         allDomainEmpty &= !field->grid->doGridHaveDataToWrite();
249         std::vector<CAxis*> vecAxis = field->grid->getAxis();
250         for (size_t i = 0; i < vecAxis.size(); ++i)
251            setAxis.insert(vecAxis[i]->getAxisOutputName());
252            // setAxis.insert(vecAxis[i]);
253         std::vector<CDomain*> vecDomains = field->grid->getDomains();
254         for (size_t i = 0; i < vecDomains.size(); ++i)
255            setDomains.insert(vecDomains[i]->getDomainOutputName());
256            // setDomains.insert(vecDomains[i]);
257
258         field->resetNStep(recordOffset);
259      }
260      nbAxis = setAxis.size();
261      nbDomains = setDomains.size();
262
263      // create sub communicator for file
264      int color = allDomainEmpty ? 0 : 1;
265      MPI_Comm_split(server->intraComm, color, server->intraCommRank, &fileComm);
266      if (allDomainEmpty) MPI_Comm_free(&fileComm);
267
268      // if (time_counter.isEmpty()) time_counter.setValue(time_counter_attr::centered);
269      if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
270    }
271
272    //! Verify state of a file
273    void CFile::checkFile(void)
274    {
275      if (mode.isEmpty() || mode.getValue() == mode_attr::write)
276      {
277        CTimer::get("Files : create headers").resume();
278        if (!isOpen) createHeader();
279        CTimer::get("Files : create headers").suspend();
280        checkSync();
281      }
282      else
283      {
284        CTimer::get("Files : open headers").resume();
285        if (!isOpen) openInReadMode();
286        CTimer::get("Files : open headers").suspend();
287      }
288      checkSplit();
289    }
290
291    /*!
292    \brief Verify if synchronisation should be done
293        If syn option is enabled, syn frequence and current time will be used to
294    calculate the moment to syn file(s)
295    \return True if it is the moment to synchronize file, otherwise false
296    */
297   bool CFile::checkSync(void)
298   {
299     CContext* context = CContext::getCurrent();
300     const CDate& currentDate = context->calendar->getCurrentDate();
301     if (!sync_freq.isEmpty())
302     {
303       if (lastSync + sync_freq.getValue() <= currentDate)
304       {
305         lastSync = currentDate;
306         data_out->syncFile();
307         return true;
308        }
309      }
310      return false;
311    }
312
313    /*!
314    \brief Verify if splitting should be done
315        If split option is enabled, split frequence and current time will be used to
316    calculate the moment to split file
317    \return True if it is the moment to split file, otherwise false
318    */
319    bool CFile::checkSplit(void)
320    {
321      CContext* context = CContext::getCurrent();
322      const CDate& currentDate = context->calendar->getCurrentDate();
323      if (!split_freq.isEmpty())
324      {
325        if (currentDate > lastSplit + split_freq.getValue())
326        {
327          lastSplit = lastSplit + split_freq.getValue();
328          std::vector<CField*>::iterator it, end = this->enabledFields.end();
329          for (it = this->enabledFields.begin(); it != end; it++)
330          {
331            (*it)->resetNStep();
332            (*it)->resetNStepMax();
333          }
334          if (mode.isEmpty() || mode.getValue() == mode_attr::write)
335            createHeader();
336          else
337            openInReadMode();
338          return true;
339        }
340      }
341      return false;
342    }
343
344   /*!
345   \brief Create header of netcdf file
346   There are some information to fill in header of each netcdf.
347   */
348   void CFile::createHeader(void)
349   {
350      CContext* context = CContext::getCurrent();
351      CContextServer* server = context->server;
352
353      if (!allDomainEmpty)
354      {
355         StdString filename = getFileOutputName();
356
357// determine splitting format in the file name  : firstPart%start_date%middlePart%end_date%lastPart
358
359         std::string strStartDate="%start_date%" ;
360         std::string strEndDate="%end_date%" ;
361
362         std::string firstPart ;
363         std::string middlePart ;
364         std::string lastPart ;
365         size_t pos1, pos2 ;
366         bool hasStartDate=false ;
367         bool hasEndDate=false ;
368         bool hasSplit = (!split_freq.isEmpty());
369                 
370         pos1=filename.find(strStartDate) ;
371         if (pos1!=std::string::npos)
372         {
373           firstPart=filename.substr(0,pos1) ;
374           pos1+=strStartDate.size() ;
375           hasStartDate=true ;
376         }
377         else pos1=0 ;
378
379         pos2=filename.find(strEndDate,pos1) ;
380         if (pos2!=std::string::npos)
381         {
382           middlePart=filename.substr(pos1,pos2-pos1) ;           
383           pos2+=strEndDate.size() ;
384           lastPart=filename.substr(pos2,filename.size()-pos2) ;
385           hasEndDate=true ;
386         }
387         else middlePart=filename.substr(pos1,filename.size()) ;
388
389         if (!hasStartDate && !hasEndDate)
390         {
391           hasStartDate=true ;
392           hasEndDate=true;
393           firstPart=middlePart ;
394           if (hasSplit) firstPart +="_";
395           middlePart="-" ;
396         }
397   
398         StdOStringStream oss;
399
400         if (!split_freq.isEmpty())
401         {
402           CDate splitEnd = lastSplit + split_freq - 1 * Second;
403
404           string splitFormat;
405           if (split_freq_format.isEmpty())
406           {
407             if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
408             else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
409             else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
410             else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
411             else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
412             else splitFormat = "%y";
413           }
414           else splitFormat = split_freq_format;
415
416           oss << firstPart ;
417           if (hasStartDate) oss << lastSplit.getStr(splitFormat) ;
418           oss << middlePart ;
419           if (hasEndDate) oss << splitEnd.getStr(splitFormat);
420           oss << lastPart ;
421
422           StdString keySuffix("CContext_"+CContext::getCurrent()->getId()+"::CFile_"+getFileOutputName()+"::") ; 
423           context->registryOut->setKey(keySuffix+"splitStart", lastSplit);
424           context->registryOut->setKey(keySuffix+"splitEnd",   splitEnd);
425         }
426         else oss<<firstPart<<lastPart ;
427
428        bool append = !this->append.isEmpty() && this->append.getValue();
429
430         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
431         bool useCFConvention = convention.isEmpty() || convention == convention_attr::CF;
432
433         bool multifile = true;
434         if (!type.isEmpty())
435         {
436           if (type == type_attr::one_file) multifile = false;
437           else if (type == type_attr::multiple_file) multifile = true;
438
439         }
440#ifndef USING_NETCDF_PAR
441         if (!multifile)
442         {
443            info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
444            multifile = true;
445          }
446#endif
447         if (multifile)
448         {
449            int commSize, commRank;
450            MPI_Comm_size(fileComm, &commSize);
451            MPI_Comm_rank(fileComm, &commRank);
452
453            if (server->intraCommSize > 1)
454            {
455              oss << "_" ;
456              int width=0; int n = commSize-1;
457              while (n != 0) { n = n / 10; width++;}
458              if (!min_digits.isEmpty())
459                if (width < min_digits) width = min_digits;
460              oss.width(width);
461              oss.fill('0');
462              oss << right << commRank;
463            }
464         }
465         oss << ".nc";
466
467         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
468
469         if (isOpen) data_out->closeFile();
470
471        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(this, oss.str(), append, useClassicFormat, useCFConvention,
472                                                              fileComm, multifile, isCollective, time_counter_name));
473        isOpen = true;
474
475        data_out->writeFile(CFile::get(this));
476
477        // Do not recreate the file structure if opening an existing file
478        if (!data_out->IsInAppendMode())
479        {
480          std::vector<CField*>::iterator it, end = this->enabledFields.end();
481          for (it = this->enabledFields.begin(); it != end; it++)
482          {
483            CField* field = *it;
484            this->data_out->writeFieldGrid(field);
485          }
486          this->data_out->writeTimeDimension();
487
488          for (it = this->enabledFields.begin(); it != end; it++)
489          {
490            CField* field = *it;
491            this->data_out->writeFieldTimeAxis(field);
492          }
493         
494          for (it = this->enabledFields.begin(); it != end; it++)
495          {
496            CField* field = *it;
497            this->data_out->writeField(field);
498          }
499
500          vector<CVariable*> listVars = getAllVariables();
501          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
502            this->data_out->writeAttribute(*it);
503
504          this->data_out->definition_end();
505        }
506        else
507        {
508          // check time axis even in append mode
509          std::vector<CField*>::iterator it, end = this->enabledFields.end();
510          for (it = this->enabledFields.begin(); it != end; it++)
511          {
512            CField* field = *it;
513            this->data_out->writeFieldTimeAxis(field);
514          }
515        }
516      }
517   }
518
519  /*!
520  \brief Open an existing NetCDF file in read-only mode
521  */
522  void CFile::openInReadMode(void)
523  {
524    CContext* context = CContext::getCurrent();
525    CContextServer* server = context->server;
526
527    if (!allDomainEmpty)
528    {
529      StdString filename = getFileOutputName();
530      StdOStringStream oss;
531      oss << filename;
532
533      if (!split_freq.isEmpty())
534      {
535        string splitFormat;
536        if (split_freq_format.isEmpty())
537        {
538          if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
539          else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
540          else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
541          else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
542          else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
543          else splitFormat = "%y";
544        }
545        else splitFormat = split_freq_format;
546        oss << "_" << lastSplit.getStr(splitFormat)
547        << "-" << (lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
548      }
549
550      bool multifile = true;
551      if (!type.isEmpty())
552      {
553        if (type == type_attr::one_file) multifile = false;
554        else if (type == type_attr::multiple_file) multifile = true;
555      }
556  #ifndef USING_NETCDF_PAR
557      if (!multifile)
558      {
559        info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
560        multifile = true;
561      }
562  #endif
563      if (multifile)
564      {
565        int commSize, commRank;
566        MPI_Comm_size(fileComm, &commSize);
567        MPI_Comm_rank(fileComm, &commRank);
568
569        if (server->intraCommSize > 1)
570        {
571          oss << "_";
572          int width = 0, n = commSize - 1;
573          while (n != 0) { n = n / 10; width++; }
574          if (!min_digits.isEmpty() && width < min_digits)
575            width = min_digits;
576          oss.width(width);
577          oss.fill('0');
578          oss << right << commRank;
579        }
580      }
581      oss << ".nc";
582
583      bool isCollective = par_access.isEmpty() || par_access == par_access_attr::collective;
584
585      if (isOpen) data_out->closeFile();
586      if (time_counter_name.isEmpty()) data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective));
587      else data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective, time_counter_name));
588      isOpen = true;
589    }
590  }
591
592   //! Close file
593   void CFile::close(void)
594   {
595     if (!allDomainEmpty)
596       if (isOpen)
597       {
598         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
599          this->data_out->closeFile();
600         else
601          this->data_in->closeFile();
602       }
603      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
604   }
605   //----------------------------------------------------------------
606
607   void CFile::readAttributesOfEnabledFieldsInReadMode()
608   {
609     if (enabledFields.empty()) return;
610
611     // Just check file and try to open it
612     CContext* context = CContext::getCurrent();
613     CContextClient* client=context->client;
614
615     // It would probably be better to call initFile() somehow
616     MPI_Comm_dup(client->intraComm, &fileComm);
617     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
618
619     checkFile();
620
621     for (int idx = 0; idx < enabledFields.size(); ++idx)
622     {
623        // First of all, find out which domain and axis associated with this field
624        enabledFields[idx]->solveGridReference();
625
626        // Read attributes of domain and axis from this file
627        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
628
629        // Now complete domain and axis associated with this field
630        enabledFields[idx]->solveGenerateGrid();
631
632        // Read necessary value from file
633        this->data_in->readFieldAttributesValues(enabledFields[idx]);
634
635        // Fill attributes for base reference
636        enabledFields[idx]->solveGridDomainAxisBaseRef();
637     }
638
639     // Now everything is ok, close it
640     close();
641   }
642
643
644   /*!
645   \brief Parse xml file and write information into file object
646   \param [in] node xmld node corresponding in xml file
647   */
648   void CFile::parse(xml::CXMLNode & node)
649   {
650      SuperClass::parse(node);
651
652      if (node.goToChildElement())
653      {
654        do
655        {
656           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
657           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
658        } while (node.goToNextElement());
659        node.goToParentElement();
660      }
661
662   }
663   //----------------------------------------------------------------
664
665   /*!
666   \brief Represent a file in form of string with all its info
667   \return String
668   */
669   StdString CFile::toString(void) const
670   {
671      StdOStringStream oss;
672
673      oss << "<" << CFile::GetName() << " ";
674      if (this->hasId())
675         oss << " id=\"" << this->getId() << "\" ";
676      oss << SuperClassAttribute::toString() << ">" << std::endl;
677      if (this->getVirtualFieldGroup() != NULL)
678         oss << *this->getVirtualFieldGroup() << std::endl;
679      oss << "</" << CFile::GetName() << " >";
680      return (oss.str());
681   }
682
683   //----------------------------------------------------------------
684
685   /*!
686   \brief Find all inheritace among objects in a file.
687   \param [in] apply (true) write attributes of parent into ones of child if they are empty
688                     (false) write attributes of parent into a new container of child
689   \param [in] parent
690   */
691   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
692   {
693      SuperClassAttribute::setAttributes(parent,apply);
694      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
695      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
696   }
697
698   //----------------------------------------------------------------
699
700   /*!
701   \brief Resolve all reference of active fields.
702      In order to know exactly which data each active field has, a search for all its
703   reference to find its parents or/and its base reference object must be done. Moreover
704   during this search, there are some information that can only be sent to server AFTER
705   all information of active fields are created on server side, e.g: checking mask or index
706   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
707   */
708   void CFile::solveOnlyRefOfEnabledFields(bool sendToServer)
709   {
710     int size = this->enabledFields.size();
711     for (int i = 0; i < size; ++i)
712     {
713       this->enabledFields[i]->solveOnlyReferenceEnabledField(sendToServer);
714//       this->enabledFields[i]->buildGridTransformationGraph();
715     }
716   }
717
718   void CFile::generateNewTransformationGridDest()
719   {
720     int size = this->enabledFields.size();
721     for (int i = 0; i < size; ++i)
722     {
723       this->enabledFields[i]->generateNewTransformationGridDest();
724     }
725   }
726
727   /*!
728   \brief Resolve all reference of active fields.
729      In order to know exactly which data each active field has, a search for all its
730   reference to find its parents or/and its base reference object must be done. Moreover
731   during this search, there are some information that can only be sent to server AFTER
732   all information of active fields are created on server side, e.g: checking mask or index
733   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
734   */
735   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
736   {
737     int size = this->enabledFields.size();
738     for (int i = 0; i < size; ++i)
739     {
740       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
741     }
742   }
743
744   /*!
745    * Constructs the filter graph for each active field.
746    *
747    * \param gc the garbage collector to use when building the filter graph
748    */
749   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
750   {
751     int size = this->enabledFields.size();
752     for (int i = 0; i < size; ++i)
753     {
754       this->enabledFields[i]->buildFilterGraph(gc, true);
755     }
756   }
757
758   /*!
759     Prefetching the data for enabled fields read from file.
760   */
761   void CFile::prefetchEnabledReadModeFields(void)
762   {
763     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
764       return;
765
766     int size = this->enabledFields.size();
767     for (int i = 0; i < size; ++i)
768       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
769   }
770
771   /*!
772     Prefetching the data for enabled fields read from file whose data is out-of-date.
773   */
774   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
775   {
776     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
777       return;
778
779     int size = this->enabledFields.size();
780     for (int i = 0; i < size; ++i)
781       this->enabledFields[i]->sendReadDataRequestIfNeeded();
782   }
783
784   void CFile::solveFieldRefInheritance(bool apply)
785   {
786      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
787      std::vector<CField*> allF = this->getAllFields();
788      for (unsigned int i = 0; i < allF.size(); i++)
789         allF[i]->solveRefInheritance(apply);
790   }
791
792   //----------------------------------------------------------------
793
794   /*!
795   \brief Add a field into file.
796      A field is added into file and it will be written out if the file is enabled and
797   level of this field is smaller than level_output. A new field won't be created if one
798   with id has already existed
799   \param [in] id String identity of new field
800   \return Pointer to added (or already existed) field
801   */
802   CField* CFile::addField(const string& id)
803   {
804     return vFieldGroup->createChild(id);
805   }
806
807   /*!
808   \brief Add a field group into file.
809      A field group is added into file and it will play a role as parents for fields.
810   A new field group won't be created if one with id has already existed
811   \param [in] id String identity of new field group
812   \return Pointer to added (or already existed) field group
813   */
814   CFieldGroup* CFile::addFieldGroup(const string& id)
815   {
816     return vFieldGroup->createChildGroup(id);
817   }
818
819   /*!
820   \brief Add a variable into file.
821      A variable is added into file and if one with id has already existed, pointer to
822   it will be returned.
823      Variable as long as attributes are information container of file.
824   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
825   to fill in (extra) information for a file.
826   \param [in] id String identity of new variable
827   \return Pointer to added (or already existed) variable
828   */
829   CVariable* CFile::addVariable(const string& id)
830   {
831     return vVariableGroup->createChild(id);
832   }
833
834   /*!
835   \brief Add a variable group into file.
836      A variable group is added into file and it will play a role as parents for variables.
837   A new variable group won't be created if one with id has already existed
838   \param [in] id String identity of new variable group
839   \return Pointer to added (or already existed) variable group
840   */
841   CVariableGroup* CFile::addVariableGroup(const string& id)
842   {
843     return vVariableGroup->createChildGroup(id);
844   }
845
846   /*!
847   \brief Send a message to create a field on server side
848   \param[in] id String identity of field that will be created on server
849   */
850   void CFile::sendAddField(const string& id)
851   {
852    CContext* context = CContext::getCurrent();
853
854    if (! context->hasServer )
855    {
856       CContextClient* client = context->client;
857
858       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
859       if (client->isServerLeader())
860       {
861         CMessage msg;
862         msg << this->getId();
863         msg << id;
864         const std::list<int>& ranks = client->getRanksServerLeader();
865         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
866           event.push(*itRank,1,msg);
867         client->sendEvent(event);
868       }
869       else client->sendEvent(event);
870    }
871
872   }
873
874   /*!
875   \brief Send a message to create a field group on server side
876   \param[in] id String identity of field group that will be created on server
877   */
878   void CFile::sendAddFieldGroup(const string& id)
879   {
880    CContext* context = CContext::getCurrent();
881    if (! context->hasServer )
882    {
883       CContextClient* client = context->client;
884
885       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
886       if (client->isServerLeader())
887       {
888         CMessage msg;
889         msg << this->getId();
890         msg << id;
891         const std::list<int>& ranks = client->getRanksServerLeader();
892         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
893           event.push(*itRank,1,msg);
894         client->sendEvent(event);
895       }
896       else client->sendEvent(event);
897    }
898
899   }
900
901   /*!
902   \brief Receive a message annoucing the creation of a field on server side
903   \param[in] event Received event
904   */
905   void CFile::recvAddField(CEventServer& event)
906   {
907
908      CBufferIn* buffer = event.subEvents.begin()->buffer;
909      string id;
910      *buffer>>id;
911      get(id)->recvAddField(*buffer);
912   }
913
914   /*!
915   \brief Receive a message annoucing the creation of a field on server side
916   \param[in] buffer Buffer containing message
917   */
918   void CFile::recvAddField(CBufferIn& buffer)
919   {
920      string id;
921      buffer>>id;
922      addField(id);
923   }
924
925   /*!
926   \brief Receive a message annoucing the creation of a field group on server side
927   \param[in] event Received event
928   */
929   void CFile::recvAddFieldGroup(CEventServer& event)
930   {
931
932      CBufferIn* buffer = event.subEvents.begin()->buffer;
933      string id;
934      *buffer>>id;
935      get(id)->recvAddFieldGroup(*buffer);
936   }
937
938   /*!
939   \brief Receive a message annoucing the creation of a field group on server side
940   \param[in] buffer Buffer containing message
941   */
942   void CFile::recvAddFieldGroup(CBufferIn& buffer)
943   {
944      string id;
945      buffer>>id;
946      addFieldGroup(id);
947   }
948
949   /*!
950   \brief Send messages to duplicate all variables on server side
951      Because each variable has also its attributes. So first thing to do is replicate
952   all these attributes on server side. Because variable can have a value, the second thing
953   is to duplicate this value on server, too.
954   */
955   void CFile::sendAddAllVariables()
956   {
957     std::vector<CVariable*> allVar = getAllVariables();
958     std::vector<CVariable*>::const_iterator it = allVar.begin();
959     std::vector<CVariable*>::const_iterator itE = allVar.end();
960
961     for (; it != itE; ++it)
962     {
963       this->sendAddVariable((*it)->getId());
964       (*it)->sendAllAttributesToServer();
965       (*it)->sendValue();
966     }
967   }
968
969   /*!
970   \brief Send a message to create a variable on server side
971      A variable always belongs to a variable group
972   \param[in] id String identity of variable that will be created on server
973   */
974   void CFile::sendAddVariable(const string& id)
975   {
976    CContext* context = CContext::getCurrent();
977
978    if (! context->hasServer )
979    {
980       CContextClient* client = context->client;
981
982       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
983       if (client->isServerLeader())
984       {
985         CMessage msg;
986         msg << this->getId();
987         msg << id;
988         const std::list<int>& ranks = client->getRanksServerLeader();
989         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
990           event.push(*itRank,1,msg);
991         client->sendEvent(event);
992       }
993       else client->sendEvent(event);
994    }
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    CContext* context = CContext::getCurrent();
1005    if (! context->hasServer )
1006    {
1007       CContextClient* client = context->client;
1008
1009       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
1010       if (client->isServerLeader())
1011       {
1012         CMessage msg;
1013         msg << this->getId();
1014         msg << id;
1015         const std::list<int>& ranks = client->getRanksServerLeader();
1016         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1017           event.push(*itRank,1,msg);
1018         client->sendEvent(event);
1019       }
1020       else client->sendEvent(event);
1021    }
1022
1023   }
1024
1025   /*!
1026   \brief Receive a message annoucing the creation of a variable on server side
1027   \param[in] event Received event
1028   */
1029   void CFile::recvAddVariable(CEventServer& event)
1030   {
1031
1032      CBufferIn* buffer = event.subEvents.begin()->buffer;
1033      string id;
1034      *buffer>>id;
1035      get(id)->recvAddVariable(*buffer);
1036   }
1037
1038   /*!
1039   \brief Receive a message annoucing the creation of a variable on server side
1040   \param[in] buffer Buffer containing message
1041   */
1042   void CFile::recvAddVariable(CBufferIn& buffer)
1043   {
1044      string id;
1045      buffer>>id;
1046      addVariable(id);
1047   }
1048
1049   /*!
1050   \brief Receive a message annoucing the creation of a variable group on server side
1051   \param[in] event Received event
1052   */
1053   void CFile::recvAddVariableGroup(CEventServer& event)
1054   {
1055
1056      CBufferIn* buffer = event.subEvents.begin()->buffer;
1057      string id;
1058      *buffer>>id;
1059      get(id)->recvAddVariableGroup(*buffer);
1060   }
1061
1062   /*!
1063   \brief Receive a message annoucing the creation of a variable group on server side
1064   \param[in] buffer Buffer containing message
1065   */
1066   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1067   {
1068      string id;
1069      buffer>>id;
1070      addVariableGroup(id);
1071   }
1072
1073   /*!
1074     \brief Sending all active (enabled) fields from client to server.
1075   Each field is identified uniquely by its string identity. Not only should we
1076   send the id to server but also we need to send ids of reference domain and reference axis.
1077   With these two id, it's easier to make reference to grid where all data should be written.
1078   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1079   */
1080   void CFile::sendEnabledFields()
1081   {
1082     size_t size = this->enabledFields.size();
1083     for (size_t i = 0; i < size; ++i)
1084     {
1085       CField* field = this->enabledFields[i];
1086       this->sendAddField(field->getId());
1087       field->sendAllAttributesToServer();
1088       field->sendAddAllVariables();
1089     }
1090   }
1091
1092   /*!
1093   \brief Dispatch event received from client
1094      Whenever a message is received in buffer of server, it will be processed depending on
1095   its event type. A new event type should be added in the switch list to make sure
1096   it processed on server side.
1097   \param [in] event: Received message
1098   */
1099   bool CFile::dispatchEvent(CEventServer& event)
1100   {
1101      if (SuperClass::dispatchEvent(event)) return true;
1102      else
1103      {
1104        switch(event.type)
1105        {
1106           case EVENT_ID_ADD_FIELD :
1107             recvAddField(event);
1108             return true;
1109             break;
1110
1111           case EVENT_ID_ADD_FIELD_GROUP :
1112             recvAddFieldGroup(event);
1113             return true;
1114             break;
1115
1116            case EVENT_ID_ADD_VARIABLE :
1117             recvAddVariable(event);
1118             return true;
1119             break;
1120
1121           case EVENT_ID_ADD_VARIABLE_GROUP :
1122             recvAddVariableGroup(event);
1123             return true;
1124             break;
1125           default :
1126              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1127           return false;
1128        }
1129      }
1130   }
1131
1132
1133
1134
1135   ///---------------------------------------------------------------
1136
1137} // namespace xios
Note: See TracBrowser for help on using the repository browser.