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

Last change on this file since 875 was 875, checked in by ymipsl, 5 years ago

Improved format when activatin splitting.
The key %start_date% and %end_date% are analysed in the filename and substitutide by coresponding date.

%start_date% and %end_date% must appear at maximum once time each, if both are specifed, %start_date% must be specified before %end_date%.
When spliting is not activated, the substring beween %start_date% and %end_date% (including date) are not output.

YM

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