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

Last change on this file since 1009 was 1009, checked in by oabramkina, 8 years ago

First working version with compression by secondary servers.

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