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

Last change on this file since 957 was 957, checked in by rlacroix, 6 years ago

Fix a possible crash caused by an infinite recursion.

The way virtual groups were handled could cause id clashes which lead to have groups containing themselves.

  • 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.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
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    CContext* context = CContext::getCurrent();
829
830    if (! context->hasServer )
831    {
832       CContextClient* client = context->client;
833
834       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
835       if (client->isServerLeader())
836       {
837         CMessage msg;
838         msg << this->getId();
839         msg << id;
840         const std::list<int>& ranks = client->getRanksServerLeader();
841         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
842           event.push(*itRank,1,msg);
843         client->sendEvent(event);
844       }
845       else client->sendEvent(event);
846    }
847
848   }
849
850   /*!
851   \brief Send a message to create a field group on server side
852   \param[in] id String identity of field group that will be created on server
853   */
854   void CFile::sendAddFieldGroup(const string& id)
855   {
856    CContext* context = CContext::getCurrent();
857    if (! context->hasServer )
858    {
859       CContextClient* client = context->client;
860
861       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
862       if (client->isServerLeader())
863       {
864         CMessage msg;
865         msg << this->getId();
866         msg << id;
867         const std::list<int>& ranks = client->getRanksServerLeader();
868         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
869           event.push(*itRank,1,msg);
870         client->sendEvent(event);
871       }
872       else client->sendEvent(event);
873    }
874
875   }
876
877   /*!
878   \brief Receive a message annoucing the creation of a field on server side
879   \param[in] event Received event
880   */
881   void CFile::recvAddField(CEventServer& event)
882   {
883
884      CBufferIn* buffer = event.subEvents.begin()->buffer;
885      string id;
886      *buffer>>id;
887      get(id)->recvAddField(*buffer);
888   }
889
890   /*!
891   \brief Receive a message annoucing the creation of a field on server side
892   \param[in] buffer Buffer containing message
893   */
894   void CFile::recvAddField(CBufferIn& buffer)
895   {
896      string id;
897      buffer>>id;
898      addField(id);
899   }
900
901   /*!
902   \brief Receive a message annoucing the creation of a field group on server side
903   \param[in] event Received event
904   */
905   void CFile::recvAddFieldGroup(CEventServer& event)
906   {
907
908      CBufferIn* buffer = event.subEvents.begin()->buffer;
909      string id;
910      *buffer>>id;
911      get(id)->recvAddFieldGroup(*buffer);
912   }
913
914   /*!
915   \brief Receive a message annoucing the creation of a field group on server side
916   \param[in] buffer Buffer containing message
917   */
918   void CFile::recvAddFieldGroup(CBufferIn& buffer)
919   {
920      string id;
921      buffer>>id;
922      addFieldGroup(id);
923   }
924
925   /*!
926   \brief Send messages to duplicate all variables on server side
927      Because each variable has also its attributes. So first thing to do is replicate
928   all these attributes on server side. Because variable can have a value, the second thing
929   is to duplicate this value on server, too.
930   */
931   void CFile::sendAddAllVariables()
932   {
933     std::vector<CVariable*> allVar = getAllVariables();
934     std::vector<CVariable*>::const_iterator it = allVar.begin();
935     std::vector<CVariable*>::const_iterator itE = allVar.end();
936
937     for (; it != itE; ++it)
938     {
939       this->sendAddVariable((*it)->getId());
940       (*it)->sendAllAttributesToServer();
941       (*it)->sendValue();
942     }
943   }
944
945   /*!
946   \brief Send a message to create a variable on server side
947      A variable always belongs to a variable group
948   \param[in] id String identity of variable that will be created on server
949   */
950   void CFile::sendAddVariable(const string& id)
951   {
952    CContext* context = CContext::getCurrent();
953
954    if (! context->hasServer )
955    {
956       CContextClient* client = context->client;
957
958       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
959       if (client->isServerLeader())
960       {
961         CMessage msg;
962         msg << this->getId();
963         msg << id;
964         const std::list<int>& ranks = client->getRanksServerLeader();
965         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
966           event.push(*itRank,1,msg);
967         client->sendEvent(event);
968       }
969       else client->sendEvent(event);
970    }
971
972   }
973
974   /*!
975   \brief Send a message to create a variable group on server side
976   \param[in] id String identity of variable group that will be created on server
977   */
978   void CFile::sendAddVariableGroup(const string& id)
979   {
980    CContext* context = CContext::getCurrent();
981    if (! context->hasServer )
982    {
983       CContextClient* client = context->client;
984
985       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
986       if (client->isServerLeader())
987       {
988         CMessage msg;
989         msg << this->getId();
990         msg << id;
991         const std::list<int>& ranks = client->getRanksServerLeader();
992         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
993           event.push(*itRank,1,msg);
994         client->sendEvent(event);
995       }
996       else client->sendEvent(event);
997    }
998
999   }
1000
1001   /*!
1002   \brief Receive a message annoucing the creation of a variable on server side
1003   \param[in] event Received event
1004   */
1005   void CFile::recvAddVariable(CEventServer& event)
1006   {
1007
1008      CBufferIn* buffer = event.subEvents.begin()->buffer;
1009      string id;
1010      *buffer>>id;
1011      get(id)->recvAddVariable(*buffer);
1012   }
1013
1014   /*!
1015   \brief Receive a message annoucing the creation of a variable on server side
1016   \param[in] buffer Buffer containing message
1017   */
1018   void CFile::recvAddVariable(CBufferIn& buffer)
1019   {
1020      string id;
1021      buffer>>id;
1022      addVariable(id);
1023   }
1024
1025   /*!
1026   \brief Receive a message annoucing the creation of a variable group on server side
1027   \param[in] event Received event
1028   */
1029   void CFile::recvAddVariableGroup(CEventServer& event)
1030   {
1031
1032      CBufferIn* buffer = event.subEvents.begin()->buffer;
1033      string id;
1034      *buffer>>id;
1035      get(id)->recvAddVariableGroup(*buffer);
1036   }
1037
1038   /*!
1039   \brief Receive a message annoucing the creation of a variable group on server side
1040   \param[in] buffer Buffer containing message
1041   */
1042   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1043   {
1044      string id;
1045      buffer>>id;
1046      addVariableGroup(id);
1047   }
1048
1049   /*!
1050     \brief Sending all active (enabled) fields from client to server.
1051   Each field is identified uniquely by its string identity. Not only should we
1052   send the id to server but also we need to send ids of reference domain and reference axis.
1053   With these two id, it's easier to make reference to grid where all data should be written.
1054   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1055   */
1056   void CFile::sendEnabledFields()
1057   {
1058     size_t size = this->enabledFields.size();
1059     for (size_t i = 0; i < size; ++i)
1060     {
1061       CField* field = this->enabledFields[i];
1062       this->sendAddField(field->getId());
1063       field->sendAllAttributesToServer();
1064       field->sendAddAllVariables();
1065     }
1066   }
1067
1068   /*!
1069   \brief Dispatch event received from client
1070      Whenever a message is received in buffer of server, it will be processed depending on
1071   its event type. A new event type should be added in the switch list to make sure
1072   it processed on server side.
1073   \param [in] event: Received message
1074   */
1075   bool CFile::dispatchEvent(CEventServer& event)
1076   {
1077      if (SuperClass::dispatchEvent(event)) return true;
1078      else
1079      {
1080        switch(event.type)
1081        {
1082           case EVENT_ID_ADD_FIELD :
1083             recvAddField(event);
1084             return true;
1085             break;
1086
1087           case EVENT_ID_ADD_FIELD_GROUP :
1088             recvAddFieldGroup(event);
1089             return true;
1090             break;
1091
1092            case EVENT_ID_ADD_VARIABLE :
1093             recvAddVariable(event);
1094             return true;
1095             break;
1096
1097           case EVENT_ID_ADD_VARIABLE_GROUP :
1098             recvAddVariableGroup(event);
1099             return true;
1100             break;
1101           default :
1102              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1103           return false;
1104        }
1105      }
1106   }
1107
1108
1109
1110
1111   ///---------------------------------------------------------------
1112
1113} // namespace xios
Note: See TracBrowser for help on using the repository browser.