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

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

Intermeadiate version for merging with new server functionalities.

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