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

Last change on this file since 987 was 987, checked in by mhnguyen, 6 years ago

First working version.
There are more things to do with it

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