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

Last change on this file since 996 was 996, checked in by mhnguyen, 7 years ago

Some modifications to make sure there is no strange _undefined_id_ name appearing in netcdf file

+) Improve the algo to search for correct name
+) Some minor changes in code

Test
+) On Curie
+) Names are correct as they should be.

  • 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.2 KB
Line 
1#include "file.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "object_factory.hpp"
7#include "context.hpp"
8#include "context_server.hpp"
9#include "nc4_data_output.hpp"
10#include "nc4_data_input.hpp"
11#include "calendar_util.hpp"
12#include "date.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "context_client.hpp"
17#include "mpi.hpp"
18
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    CContext* context = CContext::getCurrent();
833
834    if (! context->hasServer )
835    {
836       CContextClient* client = context->client;
837
838       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
839       if (client->isServerLeader())
840       {
841         CMessage msg;
842         msg << this->getId();
843         msg << id;
844         const std::list<int>& ranks = client->getRanksServerLeader();
845         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
846           event.push(*itRank,1,msg);
847         client->sendEvent(event);
848       }
849       else client->sendEvent(event);
850    }
851
852   }
853
854   /*!
855   \brief Send a message to create a field group on server side
856   \param[in] id String identity of field group that will be created on server
857   */
858   void CFile::sendAddFieldGroup(const string& id)
859   {
860    CContext* context = CContext::getCurrent();
861    if (! context->hasServer )
862    {
863       CContextClient* client = context->client;
864
865       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
866       if (client->isServerLeader())
867       {
868         CMessage msg;
869         msg << this->getId();
870         msg << id;
871         const std::list<int>& ranks = client->getRanksServerLeader();
872         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
873           event.push(*itRank,1,msg);
874         client->sendEvent(event);
875       }
876       else client->sendEvent(event);
877    }
878
879   }
880
881   /*!
882   \brief Receive a message annoucing the creation of a field on server side
883   \param[in] event Received event
884   */
885   void CFile::recvAddField(CEventServer& event)
886   {
887
888      CBufferIn* buffer = event.subEvents.begin()->buffer;
889      string id;
890      *buffer>>id;
891      get(id)->recvAddField(*buffer);
892   }
893
894   /*!
895   \brief Receive a message annoucing the creation of a field on server side
896   \param[in] buffer Buffer containing message
897   */
898   void CFile::recvAddField(CBufferIn& buffer)
899   {
900      string id;
901      buffer>>id;
902      addField(id);
903   }
904
905   /*!
906   \brief Receive a message annoucing the creation of a field group on server side
907   \param[in] event Received event
908   */
909   void CFile::recvAddFieldGroup(CEventServer& event)
910   {
911
912      CBufferIn* buffer = event.subEvents.begin()->buffer;
913      string id;
914      *buffer>>id;
915      get(id)->recvAddFieldGroup(*buffer);
916   }
917
918   /*!
919   \brief Receive a message annoucing the creation of a field group on server side
920   \param[in] buffer Buffer containing message
921   */
922   void CFile::recvAddFieldGroup(CBufferIn& buffer)
923   {
924      string id;
925      buffer>>id;
926      addFieldGroup(id);
927   }
928
929   /*!
930   \brief Send messages to duplicate all variables on server side
931      Because each variable has also its attributes. So first thing to do is replicate
932   all these attributes on server side. Because variable can have a value, the second thing
933   is to duplicate this value on server, too.
934   */
935   void CFile::sendAddAllVariables()
936   {
937     std::vector<CVariable*> allVar = getAllVariables();
938     std::vector<CVariable*>::const_iterator it = allVar.begin();
939     std::vector<CVariable*>::const_iterator itE = allVar.end();
940
941     for (; it != itE; ++it)
942     {
943       this->sendAddVariable((*it)->getId());
944       (*it)->sendAllAttributesToServer();
945       (*it)->sendValue();
946     }
947   }
948
949   /*!
950   \brief Send a message to create a variable on server side
951      A variable always belongs to a variable group
952   \param[in] id String identity of variable that will be created on server
953   */
954   void CFile::sendAddVariable(const string& id)
955   {
956    CContext* context = CContext::getCurrent();
957
958    if (! context->hasServer )
959    {
960       CContextClient* client = context->client;
961
962       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
963       if (client->isServerLeader())
964       {
965         CMessage msg;
966         msg << this->getId();
967         msg << id;
968         const std::list<int>& ranks = client->getRanksServerLeader();
969         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
970           event.push(*itRank,1,msg);
971         client->sendEvent(event);
972       }
973       else client->sendEvent(event);
974    }
975
976   }
977
978   /*!
979   \brief Send a message to create a variable group on server side
980   \param[in] id String identity of variable group that will be created on server
981   */
982   void CFile::sendAddVariableGroup(const string& id)
983   {
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.